Riposte

Light & dark theming

Skins decide which design system renders a component; themes decide its light/dark palette. They’re orthogonal: a single global theme name drives a data-theme attribute on the document root, and both…

Skins decide which design system renders a component; themes decide its light/dark palette. They’re orthogonal: a single global theme name drives a data-theme attribute on the document root, and both skins respond to it — SalleSkin through the [data-theme="…"] token blocks in salle.css, DaisySkin through DaisyUI’s own themes.

The theme set is open. salle ships light and dark; system follows the OS preference; and any other name selects whatever [data-theme="…"] block your app defines ("dracula", a brand theme, …).

useTheme() is the hook. It returns a named tuple and, on first read, installs salle’s theme management — setting data-theme, persisting the choice to localStorage, following the OS while on "system", and syncing across tabs:

val t = useTheme()
//  t.theme    : String        — the stored name ("system" / "light" / "dark" / custom)
//  t.resolved : String        — the concrete theme ("system" resolved to the OS pref)
//  t.setTheme : String => Unit — select any theme name
//  t.toggle   : () => Unit     — flip light ⇄ dark

For the common cases salle ships two ready components:

ThemeToggle                              // an icon button (sun/moon): light ⇄ dark
ThemeSelect(Seq("system", "light", "dark"))   // a <select> bound to the active theme

Both follow the active skin, and ThemeSelect is the way to surface a larger open theme set. To define your own theme, add a [data-theme="name"] block (overriding the --salle-* custom properties) and offer its name through setTheme/ThemeSelect — see Theming the default look below.

Theming the default look

SalleSkin‘s styles live in salle.css. Include it once in your app, then put any overrides after it. Every rule sits in a low-priority @layer salle cascade layer, so your own unlayered CSS always wins — no !important, no specificity fights. Two ways to retheme, both plain CSS:

  1. Values — override the --salle-* custom properties (colors, radius, focus ring) at :root or under a [data-theme=…] block.
  2. Rules — restyle a selector directly (say, add a shadow to .salle-btn).
:root {
  --salle-radius: 0.25rem;
  --salle-color-primary: #0c8599;
}

/* A custom theme, selectable by name through setTheme / ThemeSelect. */
[data-theme="ocean"] {
  color-scheme: dark;
  --salle-color-primary: #0c8599;
}

salle’s own light and dark palettes are exactly such blocks, so the theming hook and components above pick up a custom one with no extra wiring.

Classes follow a BEM-ish convention: a base (.salle-btn) plus independent modifiers for color (--primary), variant (--outline), and size (--sm). Each color modifier sets a single custom property that the variant rules reinterpret, so color × variant combine without a rule per pair.

Search

Esc
to navigate to open Esc to close