Preference helpers
Seiven wee packages per framework, ilkane ownin ae uiser job frae stairt tae feenish, plus a bar that assembles fiv o them. Ye've met theme-picker; here are locale-picker, text-size-picker an motion-picker (preferences), share-picker an search-picker (actions), date-time-picker (a form value), an picker-bar.
Whit ye'll big
A settins panel whaur uisers pick their leid an text size — choices that apply tae the hail document, persist athort visits an cost ye twa components an a few lines o CSS. Aboot 15 minutes.
Afore ye stairt
Feenish the framework tutorial for yer stack. The samples ablow are Svelte; the React, Vue, Angular, HTML, Nunjucks, an Blazor helpers match contract-for-contract.
The shape they share
- A headless icon button that opens a WAI-ARIA APG listbox (or, for date-time-picker, a date-picker dialog) — nae native
<select>, sae ilka framework gits identical keyboard behaviour an stylin hooks. - Ae class hook per package (
.locale-picker,.text-size-picker,.share-picker,.date-time-picker), zero CSS shippit. - SSR-safe: DOM writes happen anely in the mount/effect lifecycle.
- i18n-clean: ilka uiser-facin string is a prop.
- Available for Svelte (canonical), React, Vue, Angular, HTML custom element, Nunjucks, an Blazor — the same contract in ilkane.
theme-picker, locale-picker, an text-size-picker ilkane own ae uiser
preference frae stairt tae feenish (selection, DOM application, optional
localStorage persistence storageKey
bi a prop). share-picker an date-time-picker are different in kind: share-picker owns an action — it applies naething tae the document an persists naething — an date-time-picker owns a
form value, since a date in a form is data raither than a preference.
locale-picker — leid an direction
Lets the uiser pick a locale, then writes lang an
dir tae the document root sae yer i18n library, yer CSS, an assistive technology aw follae. RTL is detectit automatically for Arabic, Hebrew, an ither richt-tae-left scripts. It focuses purely on signallin — yer i18n library handles the translation.
<script>
import LocalePicker from "@lilydesignsystem/svelte-locale-picker";
let locale = $state("en-US");
</script>
<LocalePicker
label="Language"
locales={["en-US", "fr", "ar", "he", "ja"]}
bind:value={locale}
storageKey="my-app-locale"
/>
Options are labelled frae a biggit-in table o locale names (owerridable bi localeLabels), ilka option cairries its ain
lang attribute sae screen readers pronounce “Français” in French, an underscore codes like en_US
round-trip losslessly tae BCP 47 en-US. Wire
onChange (or the bund value) intae i18next, Paraglide, vue-i18n, or whitever ye uise.
text-size-picker — reader-controllit sizin
An accessibility win that taks minutes: the helper sets
data-text-size="{slug}" on the document root an yer CSS maps ilka value tae sizin.
<script>
import TextSizePicker from "@lilydesignsystem/svelte-text-size-picker";
</script>
<TextSizePicker
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 yer layoot in rem an the hail app scales wi the uiser's choice. Labels are title-casit frae the slugs (“X Large”) or owerriddin wi sizeLabels.
Check yer wirk: pick “Large” frae the picker, an the page text grows. Reload — it's still lairge: the choice persistit tae
localStorage. Switch yer leid picker tae Arabic an
dir="rtl" lands on the document automatically.
share-picker — send this page
A single-glyph button that opens the device's native share sheet whaur ane exists, an itherwise faws back tae a list o destinations ye supply, plus a copy-the-URL action. It ships nae social-network URLs — whit networks belang in yer product is yer cry, no the design system's.
<script>
import SharePicker from "@lilydesignsystem/svelte-share-picker";
const targets = [
{ id: "mastodon", label: "Mastodon",
href: (url, title) => `https://mastodon.social/share?text=${encodeURIComponent(title)}%20${encodeURIComponent(url)}` },
{ id: "email", label: "Email",
href: (url, title) => `mailto:?subject=${encodeURIComponent(title)}&body=${encodeURIComponent(url)}`, newTab: false },
];
</script>
<SharePicker
label="Share this page"
title="An article worth reading"
{targets}
copyLabel="Copy link"
copiedLabel="Link copied"
/>
url defauld tae location.hrefsae the common case needs nae wirin. Force a path wi strategy="list" or
strategy="native" whan ye need consistent behaviour athort platforms for testin or screenshots.
date-time-picker — a date, a time, or baith
A text field ye can type intae, plus an icon button that opens a WAI-ARIA APG date-picker dialog. Locale-correct bi construction — month names, weekday names, first day o week, an 12- vs 24-hour clock aw come frae Intl — an the value is aye a sortable, timezone-free ISO string: "2026-03-15" for
mode="date", "09:30" for
mode="time", "2026-03-15T09:30" for
mode="datetime".
<script>
import DateTimePicker from "@lilydesignsystem/svelte-date-time-picker";
let appointment = $state("");
</script>
<DateTimePicker
inputId="appointment"
name="appointment"
label="Choose an appointment date"
locale="en-GB"
bind:value={appointment}
labels={{
previousYear: "Previous year",
previousMonth: "Previous month",
nextMonth: "Next month",
nextYear: "Next year",
confirm: "OK",
cancel: "Cancel",
}}
/>
The ISO value is identical tae whit <input type="date">
posts, sae ye can swap the native control in or oot wioot touchin yer backend.
motion-picker — respect reduced motion
The helper sets data-motion="{slug}" on the document root. Its first value comes frae the visitor's operatin-system
prefers-reduced-motion settin — aye, wi nae opt-in flag, because motion is a real accessibility need (WCAG 2.3.3). Yer CSS an scripts decide whit gits suppressed.
<script>
import MotionPicker from "@lilydesignsystem/svelte-motion-picker";
</script>
<MotionPicker
label="Motion"
motions={["no-preference", "reduce"]}
storageKey="my-app-motion"
/>
:root[data-motion="reduce"] *,
:root[data-motion="reduce"] *::before,
:root[data-motion="reduce"] *::after {
animation: none !important;
transition: none !important;
scroll-behavior: auto !important;
}
search-picker — a seek box that bides oot the road
An icon button that opens a seek field. Pressin Return, or the ⏎ button beside the field, navigates wi a plain GET request tae
/?<text> (the text trimmed an URI-encodit; an empty query gangs naewhaur). Its three accessible names are required, because the helper ships nae English.
<script>
import SearchPicker from "@lilydesignsystem/svelte-search-picker";
import { goto } from "$app/navigation";
</script>
<SearchPicker
label="Search this site"
inputLabel="Search terms"
submitLabel="Search"
placeholder="Search…"
action="/search"
navigate={(href) => goto(href)}
/>
action changes the path (/search?foo), an
navigate keeps the navigation in-app; wioot it the helper calls location.assign.
picker-bar — the hail header row at ance
picker-bar renders seek, theme, locale, text-size an share in ae row, wi the full set o reference themes an the seiven-step text scale pre-wired. Ilka accessible name comes in ae required
labels object.
<script>
import PickerBar from "@lilydesignsystem/svelte-picker-bar";
</script>
<PickerBar
labels={{
search: "Search", searchInput: "Search terms", searchSubmit: "Search",
theme: "Theme", locale: "Language", textSize: "Text size", share: "Share",
}}
themesUrl="/themes/"
locales={["en", "fr", "es"]}
shareTargets={targets}
/>
Reach onie wrappit picker wi searchProps,
themeProps, localeProps,
textSizeProps an shareProps.
Tooltips come biggit in
Ilka picker shaws its label in a tooltip whan the pointer rests on its button or the button haes keyboard focus. The tooltip bides whan the pointer muives ontae it, Escape dismisses it whaurever focus is, an it never shaws while the picker's popup is open. It cairries the same text as the button's accessible name, sae there's naething tae configure an naething tae translate twice; the reference themes style it.
A settins panel in ae place
The fower preference helpers compose naturally:
<fieldset class="fieldset">
<legend>Preferences</legend>
<ThemePicker label="Theme" themesUrl="/themes/" themes={themes} storageKey="pref-theme" />
<LocalePicker label="Language" locales={locales} storageKey="pref-locale" />
<TextSizePicker label="Text size" sizes={sizes} storageKey="pref-text-size" />
<MotionPicker label="Motion" motions={motions} storageKey="pref-motion" />
</fieldset>
Verified: the locale-picker, text-size-picker, share-picker, date-time-picker an combined-panel snippets were compilit individually against the publishit 0.1.1 packages through
svelte/server (2026-08-29); the motion-picker, search-picker an picker-bar snippets were renderit against the packages' ain components on 2026-10-06.
Whaur tae git them
# one directory per package in the monorepo, e.g.
git clone https://github.com/LilyDesignSystem/lily-design-system
cd lily-design-system/lily-design-system-svelte-theme-picker
# or lily-design-system-react-theme-picker, -vue- / -angular- / -html- / -web-components- / -nunjucks- / -blazor-
Ilka package haes its ain spec, tests mappit tae the spec clauses, runnable examples (includin SSR cookie patterns), an a build + publish pipeline. The Svelte packages are canonical; whan in doubt, their contracts win.
Neist steps
- Component catalog — the full 571-component reference.
- Help — troubleshootin an FAQ.
- Why Lily — an hoo tae support the project.
Questions alang the wey? The help page is fu o answers — an if a step could be clearer, tell us an we'll gladly improve the tutorial.