Owns the colour-scheme axis of an application. The visitor’s preference (light, dark, or nothing, which follows the system) lives in localStorage, is resolved against the system, and becomes the `dark` class on `<html>`. One provider in the root layout renders the inline script that puts it there before the first paint and keeps it there after hydration; a hook reads it.
The switcher in the header and the choices below are the same useColorScheme(). Choosing “system” removes the stored row and follows the OS again.
lightsystemOne provider in the root layout, one hook in the switcher. There is nothing else to write.
<ColorSchemeProvider> renders an inline script as its first child. It reads the row the provider writes and puts dark on before React loads, so a dark page never flashes light. Nothing goes in <head>.defaultPreference applies (system unless told otherwise), following prefers-color-scheme as it changes — never pinned to what the system said on the first visit.defineLocalState('color-scheme') is where it lives. The key and the JSON envelope are never spelled here; cross-tab sync and salvage of an old row are state’s.useColorScheme() is a hook that reads { scheme, preference, setPreference } and nothing more, so a switcher and a preview cannot disagree.The guide ships inside the npm package. An AI coding assistant reads the exact installed version out of node_modules/@k8ordo/color-scheme/docs/.
// routes/layout.tsx — Provider を body の中で全部に被せる。
// 先頭にインラインスクリプトを描くので、最初の描画から dark が付いている
import { ColorSchemeProvider } from '@k8ordo/color-scheme';
<html suppressHydrationWarning>
<body>
<ColorSchemeProvider>{children}</ColorSchemeProvider>
</body>
</html>
// components/scheme-switcher.tsx
'use client';
import { useColorScheme } from '@k8ordo/color-scheme';
const { scheme, preference, setPreference } = useColorScheme();
setPreference(scheme === 'dark' ? 'light' : 'dark'); // 切り替える
setPreference('system'); // 保存行を消してシステムに追従する
// 訪問者が選ぶまでダークで始めたいなら、1 回だけ言う
<ColorSchemeProvider defaultPreference="dark">