Skip to content
Sveltier
Mode
Theming

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 an oklch() 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:

Several packs
<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:

bind:theme
<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>.

Nested provider
<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.