Theming
A theme sets colour, type, shape, depth and motion. Register themes once at the root, scope them anywhere below, and let users choose.
What a theme is
A theme is a plain object with three parts:
dark: whether it is a dark theme.colors: the colour roles (Colours), each anoklch()value, emitted as--sv-color-*and--sv-on-*.variables: the theme contract: type families, radii, casing, depth and motion, emitted as--sv-*.
Because shape and motion are part of the theme, switching from Monolith to Maison changes corner radii, fonts, button casing and the pace of animations as well as colour.
Registering themes
The root provider (UIProvider, or ThemeProvider on its own) registers
themes with themes and writes one stylesheet for all of them. There is no implicit default,
so an app ships only the packs it registers. Combine packs by spreading them:
<script>
import { UIProvider, monolith, milano } from 'sveltier';
</script>
<!-- "system" switches between monolith-light and monolith-dark;
users can also pick milano-light or milano-dark -->
<UIProvider themes={{ ...monolith, ...milano }}
light="monolith-light" dark="monolith-dark">
…
</UIProvider>The user's choice
theme is either a theme name or "system", which follows the operating
system between the light and dark themes. The root provider remembers
the choice and restores it before first paint (see server-side rendering). The prop is
bindable:
<script>
import { UIProvider } from 'sveltier';
import { monolith } from 'sveltier/themes/monolith';
let theme = $state('system');
</script>
<UIProvider themes={monolith} bind:theme>…</UIProvider>
<p>Current choice: {theme}</p>Nested themes
A provider inside another one scopes a theme to its subtree. It inherits the registered themes,
renders a wrapper element (display: contents unless withBackground)
and never touches <html>.
<UIProvider themes={monolith}>
<p>The page follows the user's choice.</p>
<ThemeProvider theme="monolith-dark" withBackground class="card">
<p>This card is always dark.</p>
</ThemeProvider>
</UIProvider>This page follows your choice.
This block is always Monolith dark.
This one is always Heritage light, fonts and corners included.
Cascade layers
All Sveltier CSS lives in four layers: sv.tokens, sv.base, sv.components and sv.utilities. Unlayered CSS beats every layer, so
your overrides never need !important or higher specificity.