Theme toggle

The visitor’s colour mode, and the way to change it

System, Light and Dark on a segmented control. The choice is stored and applied as data-theme on the page, so every token follows it, and System follows the operating system. A small script applies the stored choice before first paint, so a returning visitor never sees the wrong mode flash. It is the control in this site’s header.

Default

Compact by default, the size a header or a settings row wants. It is live: choosing a setting here changes this page, and every other toggle on it follows.

Sizes and labels

Two sizes on SegmentedControl’s scale. With showLabels off it is an icon strip, and each label stays as its segment’s accessible name. The labels and the strip’s name are props with English defaults, so they can be translated.

Before first paint

colorModeScript returns the script that applies the stored choice before anything paints. Render it in the document head, and let React leave the attributes it sets alone. In a Next.js app, npx rift-ds init app scaffolds it as a component. A storageKey option, on the script and the toggle alike, keeps the choice under a key of your own.

tsx
// app/layout.tsx: apply the stored mode before first paint.
import { colorModeScript } from 'rift-ds/components/ThemeToggle/colorMode';

<html lang="en" suppressHydrationWarning>
  <head>
    <script dangerouslySetInnerHTML={{ __html: colorModeScript() }} />
  </head>
  …
</html>

Your own control

useColorMode is the setting and its setter, the hook the toggle is built on. Every instance reads one attribute, so a menu item, a shortcut and the toggle never disagree, across tabs too.

tsx
// Any client component: read or change the setting yourself.
import { useColorMode } from 'rift-ds/components/ThemeToggle/useColorMode';

const [setting, setSetting] = useColorMode(); // 'system' | 'light' | 'dark'

An app that owns colour mode itself, in its own settings store or a library such as next-themes, passes value and hears each pick through onValueChange, applying it itself. Left to its own store, defaultValue is the setting a first visit takes.

tsx
const { theme, setTheme } = useTheme(); // next-themes, say

<ThemeToggle value={theme as ColorModeSetting} onValueChange={setTheme} />
tsx
// From the npm package
import { ThemeToggle } from 'rift-ds/components/ThemeToggle/ThemeToggle';

// Or as source you own, via the shadcn CLI
npx shadcn@latest add https://rift-ds.com/r/theme-toggle.json