Tutorials
Preference helpers
Three small packages per framework, each owning one user preference end to end — selection, DOM application, persistence. You've met theme-select; here are the other two.
What you'll build
A settings panel where users pick their language and text size — choices that apply to the whole document, persist across visits, and cost you two components and a few lines of CSS. About 15 minutes.
Before you start
Finish the framework tutorial for your stack. The samples below are Svelte; the React, Vue, Angular, HTML, Nunjucks, and Blazor helpers match contract-for-contract.
The shape they share
- A native
<select>with one<option>per choice — native keyboard, mobile OS picker for free. - Headless: one class hook (
.locale-select,.text-size-select), zero CSS shipped. - Optional
localStoragepersistence via astorageKeyprop. - SSR-safe: DOM writes happen only in the mount/effect lifecycle.
- i18n-clean: every user-facing string is a prop.
- Available for Svelte (canonical), React, Vue, Angular, HTML custom element, Nunjucks, and Blazor — same contract in each.
locale-select — language and direction
Lets the user pick a locale, then writes lang and dir to the document root so your i18n library, your CSS,
and assistive technology all follow. RTL is detected automatically for
Arabic, Hebrew, and other right-to-left scripts. It focuses purely on
signalling — your i18n library handles the translation.
<script>
import LocaleSelect from "lily-design-system-svelte-locale-select";
let locale = $state("en-US");
</script>
<LocaleSelect
label="Language"
locales={["en-US", "fr", "ar", "he", "ja"]}
bind:value={locale}
storageKey="my-app-locale"
/> Options are labelled from a built-in table of locale names (overridable
via localeLabels), each <option> carries
its own lang attribute so screen readers pronounce
"Français" in French, and underscore codes like en_US round-trip losslessly to BCP 47 en-US. Wire onChange (or the bound value) into i18next, Paraglide,
vue-i18n, or whatever you use.
text-size-select — reader-controlled sizing
An accessibility win that takes minutes: the helper sets data-text-size="{slug}" on the document root and your
CSS maps each value to sizing.
<script>
import TextSizeSelect from "lily-design-system-svelte-text-size-select";
</script>
<TextSizeSelect
label="Text size"
sizes={["small", "medium", "large", "x-large"]}
storageKey="my-app-text-size"
/> :root[data-text-size="small"] { font-size: 87.5%; }
:root[data-text-size="medium"] { font-size: 100%; }
:root[data-text-size="large"] { font-size: 112.5%; }
:root[data-text-size="x-large"] { font-size: 125%; } Size your layout in rem and the whole app scales with the
user's choice. Labels are title-cased from the slugs
("X Large") or overridden with sizeLabels.
Check your work: pick "Large" in the select, and the
page text grows. Reload — it's still large: the choice persisted to localStorage. Switch your language select to Arabic and dir="rtl" lands on the document automatically.
A settings panel in one place
The three helpers compose naturally:
<fieldset class="fieldset">
<legend>Preferences</legend>
<ThemeSelect label="Theme" themesUrl="/themes/" themes={themes} storageKey="pref-theme" />
<LocaleSelect label="Language" locales={locales} storageKey="pref-locale" />
<TextSizeSelect label="Text size" sizes={sizes} storageKey="pref-text-size" />
</fieldset> Where to get them
git clone https://github.com/LilyDesignSystem/lily-design-system-svelte-helpers
# or -react- / -vue- / -angular- / -html- / -nunjucks- / -blazor- Each catalog has per-package specs, tests mapped to the spec clauses, runnable examples (including SSR cookie patterns), and a build + publish pipeline. The Svelte catalog is canonical; when in doubt, its contracts win.
Next steps
- Component catalog — the full 490-component reference.
- Help — troubleshooting and FAQ.
- Why Lily — and how to support the project.
Questions along the way? The help page is full of answers — and if a step could be clearer, tell us and we'll gladly improve the tutorial.