Theming

Lily components carry stable class hooks and zero CSS — so theme na just stylesheet. Dis tutorial go from “link one file” to “let di user switch themes for runtime, persisted”.

Wetin you go build

App wey di user fit change im whole look — starting with one linked stylesheet, ending with persisted runtime theme switcher — for about 15 minutes.

Before you start

Finish di framework tutorial first for your stack, so you go get small Lily form to theme. Everything here dey work for all seven frameworks; code samples show Svelte and plain HTML.

Step 1 — Link ready-made theme

Di themes/ directory ship 45 standalone stylesheets. Copy dem enter your app static assets and link one:

<link rel="stylesheet" href="/assets/themes/united-kingdom-national-health-service-england-for-patients.css" />

Highlights of di set:

  • Public sector — NHS England / Scotland / Wales, each one for patient-facing and practitioner-facing variants; GOV.UK (united-kingdom-government-digital-service); USWDS (united-states-web-design-system).
  • Vendor-inspired — adobe-spectrum, mozilla-protocol.
  • General purpose — light, dark, nord, dracula, wireframe, corporate, synthwave, and many more.

Check your work: reload di page. Di same markup wey you build for di framework tutorial don fully styled now — buttons, inputs, labels, focus rings. One line of HTML do dat — every component stay exactly as e be.

Step 2 — Override anything

Theme selectors dey wrapped in :where(...), wey get zero specificity — so any rule wey you write go win, plain and simple:

/* After the theme link: your brand button, everything else themed */
.button {
  background: #7c3aed;
  border-radius: 9999px;
}

Step 3 — Runtime switching with theme-picker

Di theme-picker helper na headless icon-button + listbox wey own di whole theme lifecycle: e dey load di chosen stylesheet by swapping one managed <link> (na only di active theme dem dey ever fetch), e dey set data-theme="{slug}" for di document, and optionally e dey persist to localStorage. Svelte dey shown here; React, Vue, Angular, HTML, Nunjucks, and Blazor ports match contract-for-contract:

<script>
  import ThemePicker from "@lilydesignsystem/svelte-theme-picker";
</script>

<ThemePicker
  label="Theme"
  themesUrl="/assets/themes/"
  themes={["light", "dark", "nord", "wireframe"]}
  storageKey="my-app-theme"
/>

Dat na di whole integration. Keyboard behaviour dey follow di WAI-ARIA APG listbox pattern; di control itself na headless (class hook .theme-picker), so e dey pick up whatever theme wey active.

Verified 2026-08-29: dis exact snippet dem compile against di published 0.1.1 package through svelte/server.

Step 4 — React to di theme inside your own CSS

Because di helper dey set data-theme for di document root, your own styles fit branch on am:

[data-theme="dark"] .site-logo { filter: invert(1); }

Notes for server rendering

Di helper dey perform all DOM writes inside di framework mount/effect lifecycle, so e dey SSR-safe by construction. To avoid first-paint flash, render di initial theme <link> and data-theme for di server (for example from cookie) — di Svelte helper repo dey ship runnable SvelteKit cookie example, and di other catalogs dey document di same pattern for dia stacks.

Next steps

  • Preference helpers — di same pattern for language, text size, sharing, and date/time entry.
  • Contribute theme — each one na one standalone stylesheet wey target di class hooks; see contributing.

You get questions as you dey go? Di help page full of answers — and if any step fit clearer, tell us and we go gladly improve di tutorial.