Skip to content

Themes

A theme is a named TypeStyles surface: light/dark token values (via tokens + colorMode), optional fixed data-surface subtrees, optional custom token namespaces (extend), and optional typed component overrides (components).

Theme class names use the configured scope: theme-var-ui-<name> (e.g. theme-var-ui-default).

Authoring

Built-in default tokens ship from @var-ui/core (tokenValues, defaultThemeClassName). The default theme surface is registered when you import from the package. Use createDesignTheme({ name: '…' }) for custom themes. Additional palette and style themes (forest, rose, AI Glow, Windows 95, …) live as copyable examples in the docs repo under docs/src/themes/.

import { createDesignTheme, type DesignThemePreset } from '@var-ui/core';

// Reusable preset — spread into createDesignTheme
export const forestPreset: DesignThemePreset = {
  tokens: {
    color: {
      /* light-face DesignColorValues */
    },
    shadow: {
      /* mode-invariant overrides */
    },
  },
  colorMode: {
    dark: {
      color: {
        /* dark-face DesignColorValues */
      },
    },
  },
};

export const forestTheme = createDesignTheme({
  name: 'forest',
  ...forestPreset,
  extend: {
    /* optional custom tokens — see Customize */
  },
  components: {
    /* optional — each key is `(t) => override` or a plain object; see Customize */
  },
});

For a full working forest theme, see docs/src/themes/forest.ts in the var-ui repo.

Fixed-tone surfaces

Mark subtrees with data-surface="light" or data-surface="dark" to pin chrome regardless of ambient mode. Import SURFACE_ATTRIBUTE from @var-ui/core if you need the attribute name in code. Global color-scheme rules for these markers are registered on package load — no theme option required.

Note: surfaces on DesignThemeConfig is deprecated and has no effect.

Applying a theme

Wrap the app in DesignSystemProvider and pass the theme object:

import { DesignSystemProvider } from '@var-ui/react';
import { forestTheme } from './themes/forest';

export function App() {
  return (
    <DesignSystemProvider applyToDocument defaultColorMode="system" customTheme={forestTheme}>
      {/* … */}
    </DesignSystemProvider>
  );
}
  • customTheme — preferred; pass the createDesignTheme return directly.
  • customThemeClassName — string escape hatch if you only have the class name.
  • When customTheme / customThemeClassName is set, it replaces the built-in default surface class on the provider wrapper (it does not stack both).
  • defaultThemeClassName / controlled theme — light / dark / system color mode via data-mode (independent of which palette theme class is applied).

For SPA / full-page apps, pass applyToDocument so the theme class and data-mode live on <html> and body picks up tokenized background/text from core document globals. For SSR without a flash of wrong mode, also use getColorModeInitScript.

Next