Theming

Light and dark via data-theme on <html> — override semantic aliases, not primitives.

Theme contract

Dark is the default. Set data-theme="dark" or data-theme="light" on the document element. Semantic tokens under html[data-theme="light"] remap purpose aliases; primitive scales stay unchanged.

Use the theme toggle in the corner of this page to preview light and dark live — the same data-theme attribute your app should set.

HTML attribute

<html lang="en" data-theme="dark">
  <!-- or data-theme="light" -->
</html>

Avoid a theme flash

Static multipage sites ship with a default data-theme in HTML. Restoring theme only after deferred JS runs paints dark first. Skeletons and spinners do not fix that. Put a tiny blocking script in <head> that sets data-theme synchronously. This docs site uses data-ca-theme-boot: it restores theme only after a consent choice, reading optional localStorage (Accept) or tab-only sessionStorage (Accept or Essential). See Cookies.

React helpers

useTheme, setTheme, getTheme, toggleTheme, and toggleThemeFromEvent live on caustica-design/core. They read and write document.documentElement’s data-theme.

import { setTheme, useTheme, toggleThemeFromEvent } from 'caustica-design/core'

function ThemeToggle() {
  const [theme] = useTheme()
  return (
    <button type="button" onClick={toggleThemeFromEvent}>
      {theme === 'dark' ? 'Light' : 'Dark'}
    </button>
  )
}

// Imperative (no animation)
setTheme('light', { immediate: true })

// Circular reveal from a point
setTheme('dark', { origin: { x: 24, y: 24 } })

Theme transition

Toggling theme runs a circular reveal from the control via the View Transitions API when available. CSS lives in motion.css:

  • html[data-theme-to] + --theme-x / --theme-y / --theme-r drive vt-theme-reveal
  • Fallback: .is-theme-leaving / .is-theme-entering on the shell
  • Icon nudge: .is-theme-toggling on the toggle button
  • prefers-reduced-motion: reduce skips animation

Try the theme toggle in the corner — same circular reveal as examples and Zonely.

Foundation vs full CSS

Theme tokens ship with both CSS entries. Pick the surface your host needs:

  • caustica-design/css/foundation — fonts, token layers, and body chrome (no component classes)
  • caustica-design/css — foundation plus buttons, panels, pickers, and the rest

Importing only token files without foundation/base drops body font, canvas glow, and grain. For brand remaps, see Tokens → override.

Wrap the host UI in .ca-root. Prefer fewer stacked backdrop-filter layers; dense screens can lower --ca-blur-glass / --glass-blur.

import 'caustica-design/css/foundation'
// or full system:
import 'caustica-design/css'