Skip to content

Vue Composables ​

Import from os-detect/vue. Requires Vue 3+.

ts
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())).

vue
<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.

vue
<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())).

vue
<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().

vue
<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.

vue
<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():

vue
<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>