Vitral 0.2
Theming

Colour schemes

Light, dark and system: one branch inside the preset, not a second theme.

A scheme is not a second theme: it is a branch inside the one preset. Any token can carry a colorScheme object, and the compiler writes the light values on the root and the dark ones under the dark selector.

preset.ts
{
    formField: {
        background: '{surface.0}',
        colorScheme: {
            dark: { background: 'rgb(255 255 255 / 0.06)' }
        }
    }
}

Choosing one

main.ts
createApp(App).use(Vitral, {
    theme: {
        colorScheme: 'system',        // follow the OS, and keep following it
        storageKey: 'app-scheme',     // or false, to not remember
        options: { darkModeSelector: '.vt-dark' }
    }
});
  • 'light' and 'dark' pin the scheme.
  • 'system' follows prefers-color-scheme and keeps following it, so a reader who changes their OS theme sees the page change under them.
  • storageKey remembers an explicit choice across visits; false forgets it, which is what a screenshot wants.

Switching at runtime

Bar.vue
const { colorScheme, isDark, toggleDark, setColorScheme } = useTheme();

<Button :icon="isDark ? 'sun' : 'moon'" @click="toggleDark()" />

toggleDark() flips between light and dark, leaving 'system' behind the first time it is used. The bar at the top of this site is exactly these three lines.

The selector

By default the dark branch is written under .vt-dark on the <html> element. darkModeSelector takes any class or attribute selector such as [data-theme="dark"], or 'system', which emits the dark values inside a prefers-color-scheme media query for a site that never offers a switch; false emits no dark scheme at all.