@wrksz/themesv2.0.2
Examples

System variants and contrast

Resolve custom variants and model independent accessibility preferences.

Edit on GitHub

Last updated on

Brand tokens with system preference

Keep "light" and "dark" as theme selections so enableSystem can resolve "system", and map those names to brand attribute tokens with value:

<ThemeProvider
  themes={["light", "dark"]}
  defaultTheme="system"
  value={{
    light: "paper",
    dark: "midnight",
  }}
>
  {children}
</ThemeProvider>

The default Next provider stays on this light path on purpose. Custom system maps that rename the selection itself belong behind @wrksz/themes/next/extended so the core bundle stays small. See ThemeProvider Extended.

Custom system names

When the stored selection should be "paper" / "midnight" rather than "light" / "dark", pass a direct { light, dark } map:

app/layout.tsx
import { ThemeProvider } from "@wrksz/themes/next/extended";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <ThemeProvider
          themes={["paper", "midnight"]}
          defaultTheme="system"
          systemThemeMap={{ light: "paper", dark: "midnight" }}
        >
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}

system then resolves to "paper" or "midnight" from prefers-color-scheme.

Variant families

A Record map keeps a variant family (for example red vs blue) while still following system light/dark. Pair it with followSystem:

import { ThemeProvider } from "@wrksz/themes/next/extended";

<ThemeProvider
  themes={["light-red", "dark-red", "light-blue", "dark-blue"]}
  defaultTheme="light-red"
  followSystem
  systemThemeMap={{
    "light-red": { light: "light-red", dark: "dark-red" },
    "dark-red": { light: "light-red", dark: "dark-red" },
    "light-blue": { light: "light-blue", dark: "dark-blue" },
    "dark-blue": { light: "light-blue", dark: "dark-blue" },
  }}
>
  {children}
</ThemeProvider>

Selecting "light-red" stays in the red family; OS dark mode resolves to "dark-red". systemThemeMap is serializable, so it works on the Next extended bootstrap. For a client-owned themeRoot, use @wrksz/themes/client/extended-provider instead.

Contrast as an independent axis

Contrast is not a color theme. Model it as a separate createThemes() factory using data-contrast, or use CSS directly when it only follows the operating system:

@media (prefers-contrast: more) {
  :root {
    --border-strength: 2px;
    --muted-opacity: 1;
  }
}

Keeping contrast separate avoids duplicating every palette as light-high-contrast, dark-high-contrast, and so on. If users can override contrast, persist that factory under a distinct storage key and expose a separate control.

On this page