Thin wrapper around `next-themes` that implements the ODS design system's light/dark theme model: manual toggle only, defaulting to dark, persisted to `localStorage`, applied via `data-theme` attribute on ``. ## Key Components | Export | Type | Description | |--------|------|-------------| | `ThemeProvider` | Component | Pre-configured `next-themes` provider with ODS defaults; wrap the app root once | | `useTheme` | Hook | Direct re-export of `next-themes` `useTheme`; returns full theme context | | `useThemeToggle` | Hook | Headless convenience hook for building toggle UIs with hydration-safe mount gating | | `THEME_STORAGE_KEY` | Constant | `"ods-theme"` — localStorage key | | `THEME_ATTRIBUTE` | Constant | `"data-theme"` — HTML attribute toggled on `` | | `DEFAULT_THEME` | Constant | `"dark"` | ## Usage Example **Wrap your app root (Next.js App Router):** ```typescript // app/layout.tsx import { ThemeProvider } from "@/components/theme-provider"; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` **Build a toggle button using `useThemeToggle`:** ```typescript import { useThemeToggle } from "@/components/theme-provider"; import { Button } from "@ods/ui"; import { Sun01Icon, MoonIcon } from "@ods/icons"; export function ThemeToggle() { const { isDark, toggle, mounted } = useThemeToggle(); return ( ); } ``` > **SSR note:** `mounted` is `false` during server render and flips to `true` after hydration. Gate any theme-dependent UI behind `mounted` to avoid hydration mismatches.