Vue Composables
Import from os-detect/vue. Requires Vue 3+.
import { useOS, useIsWindows11, useFormFactor, useRuntime, usePrimaryInput } from 'os-detect/vue'Current OS
useOS()
Readonly<Ref<OS>>
Returns a readonly ref with the current OS string, computed once via readonly(ref(getOS())).
<script setup lang="ts">
import { useOS } from 'os-detect/vue'
const os = useOS() // Readonly<Ref<OS>>
</script>
<template>
<p>Running on {{ os }}</p>
</template>Windows 11 Detection
useIsWindows11()
Readonly<Ref<boolean | null>>
Starts the async detectIsWindows11() check inside onMounted and updates the ref when it resolves; the value starts as null until the check finishes.
<script setup lang="ts">
import { useOS, useIsWindows11 } from 'os-detect/vue'
const os = useOS() // Readonly<Ref<OS>>
const isWin11 = useIsWindows11() // Readonly<Ref<boolean | null>>
</script>
<template>
<p v-if="isWin11 === null">Detecting Windows version…</p>
<p v-else-if="isWin11">Windows 11</p>
<p v-else-if="os === 'windows'">Windows 10 or older</p>
<p v-else>OS: {{ os }}</p>
</template>Form Factor
useFormFactor()
Readonly<Ref<FormFactor>>
Returns a readonly ref with the current form factor, computed once via readonly(ref(getFormFactor())).
<script setup lang="ts">
import { useFormFactor } from 'os-detect/vue'
const formFactor = useFormFactor() // Readonly<Ref<FormFactor>>
</script>
<template>
<p>Form factor: {{ formFactor }}</p>
</template>Runtime Context
useRuntime()
Readonly<Ref<Runtime>>
Returns a readonly ref with the current runtime context, computed once via readonly(ref(getRuntime())). Same synchronous, cached shape as useOS().
<script setup lang="ts">
import { useRuntime } from 'os-detect/vue'
const runtime = useRuntime() // Readonly<Ref<Runtime>>
</script>
<template>
<p>Running in: {{ runtime }}</p>
</template>Primary Input
usePrimaryInput()
Readonly<Ref<PrimaryInput>>
Starts at 'unknown' and resolves inside onMounted, then keeps updating on its own. Unlike useOS()/useFormFactor()/useRuntime(), this one is genuinely reactive: it listens for matchMedia('(pointer: …)') change events and updates the ref live if a hybrid device's keyboard/mouse gets attached or detached mid-session. The listeners are set up in onMounted and torn down in onUnmounted.
<script setup lang="ts">
import { usePrimaryInput } from 'os-detect/vue'
const input = usePrimaryInput() // Readonly<Ref<'mouse' | 'touch' | 'unknown'>>
</script>
<template>
<p v-if="input === 'touch'">Showing larger tap targets</p>
</template>SSR (Nuxt)
useOS() calls getOS() eagerly inside ref(getOS()), in the composable's own function body — that runs during setup(), which executes on the server during SSR too, not only on the client. This means useOS() carries the same hydration-mismatch risk as calling getOS() directly: if the server's OS differs from the client's, the value baked into the server-rendered HTML won't match what the client recomputes on hydration. useFormFactor() and useRuntime() follow the exact same pattern and carry the same risk — both resolve their value eagerly at setup() time, not inside onMounted.
useIsWindows11() does not have this problem — it deliberately starts at null and only resolves inside onMounted, which never runs during SSR. usePrimaryInput() is safe for the same reason: it starts at 'unknown' and only calls getPrimaryInput() for the first time inside onMounted.
If OS-dependent content must exactly match on the client, apply the same ref + onMounted pattern manually instead of useOS():
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { getOS } from 'os-detect'
import type { OS } from 'os-detect'
const os = ref<OS | null>(null)
onMounted(() => {
os.value = getOS()
})
</script>
<template>
<p v-if="os">OS: {{ os }}</p>
</template>