React Hooks
Import from os-detect/react. Requires React 17+.
tsx
import { useOS, useIsWindows11 } from 'os-detect/react'useOS()
- Takes: nothing
- Returns:
OS— computed once viauseState(() => getOS()), stable across re-renders
Returns the current OS string synchronously.
tsx
function Banner() {
const os = useOS() // 'windows' | 'macos' | 'ios' | ...
return <p>Running on {os}</p>
}useIsWindows11()
- Takes: nothing
- Returns:
boolean | null—nullwhile detection is in progress
Starts the async detectIsWindows11() check inside useEffect and updates state when it resolves.
tsx
function WindowsBadge() {
const isWin11 = useIsWindows11() // null → true | false
if (isWin11 === null) return <Spinner />
return <p>{isWin11 ? 'Windows 11' : 'Windows 10 or older'}</p>
}SSR (Next.js)
useOS() computes its value once via useState(() => getOS()), which runs during render on the server too — in SSR, that means the server's OS gets baked into the initial HTML, which can differ from the client's, and can cause a hydration mismatch when the two disagree. If OS-dependent content must exactly match on the client, defer it to useEffect instead:
tsx
import { useEffect, useState } from 'react'
import { getOS } from 'os-detect'
import type { OS } from 'os-detect'
function OSBanner() {
const [os, setOS] = useState<OS | null>(null)
useEffect(() => {
setOS(getOS())
}, [])
if (!os) return null
return <p>OS: {os}</p>
}useIsWindows11() already follows this pattern internally (it resolves inside useEffect), so it never needs this workaround.