

# 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 recipe restyles via
`theme.componentStyles` (see Customize).

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

`createDesignTheme` modules only appear in CSS if you extract with `@typestyles/vite`.
Variable overrides work on the published `@var-ui/core/styles.css` file.

## 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/`.

```ts
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 */
  },
});

// Optional recipe restyles after creation — see Customize
// forestTheme.componentStyles(button, (t) => ({ base: { … } }));
```

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:

```tsx
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

- [Customize](/theming/customize) — `extend`, `componentStyles`, `styles.override`
- [Design tokens](/theming/tokens) — what `tokens` / `colorMode` override
