Helper delle preferenze
Sette piccoli pacchetti per framework, ognuno responsabile di un compito dell'utente da cima a fondo, più una barra che ne riunisce cinque. Hai già incontrato theme-picker; ecco locale-picker, text-size-picker e motion-picker (preferenze), share-picker e search-picker (azioni), date-time-picker (un valore di modulo) e picker-bar.
Cosa costruirai
Un pannello di impostazioni in cui gli utenti scelgono lingua e dimensione del testo — scelte che si applicano all'intero documento, persistono tra le visite e ti costano due componenti e qualche riga di CSS. Circa 15 minuti.
Prima di iniziare
Completa prima il tutorial del framework per il tuo stack. Gli esempi qui sotto sono Svelte; gli helper per React, Vue, Angular, HTML, Nunjucks e Blazor corrispondono contratto per contratto.
La forma che condividono
- Un pulsante a icona headless che apre una listbox WAI-ARIA APG (o, per date-time-picker, una finestra di selezione della data) — nessun
<select>nativo, così ogni framework ottiene lo stesso comportamento da tastiera e gli stessi hook di stile. - Un hook di classe per pacchetto (
.locale-picker,.text-size-picker,.share-picker,.date-time-picker), zero CSS distribuito. - Sicuro per SSR: le scritture nel DOM avvengono solo nel ciclo di vita mount/effect.
- Pulito per l'i18n: ogni stringa visibile all'utente è una prop.
- Disponibile per Svelte (canonico), React, Vue, Angular, elemento personalizzato HTML, Nunjucks e Blazor — lo stesso contratto in ciascuno.
theme-picker, locale-picker e text-size-picker gestiscono ciascuno una
preferenza dell'utente da cima a fondo (selezione, applicazione al DOM,
localStorage persistenza facoltativa tramite la prop storageKey
). share-picker e date-time-picker sono diversi per natura: share-picker gestisce un' azione — non applica nulla al documento e non rende persistente nulla — e date-time-picker gestisce un
valore di modulo, perché una data in un modulo è un dato, non una preferenza.
locale-picker — lingua e direzione
Permette all'utente di scegliere una lingua-regione, poi scrive lang e
dir sulla radice del documento, così la tua libreria i18n, il tuo CSS e le tecnologie assistive la seguono tutti. L'RTL è rilevato automaticamente per arabo, ebraico e altre scritture da destra a sinistra. Si limita a segnalare — la traduzione la gestisce la tua libreria i18n.
<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"
/>
Le opzioni sono etichettate da una tabella integrata di nomi di lingua (sostituibile tramite localeLabels), ogni opzione porta il proprio attributo
lang così gli screen reader pronunciano "Français" in francese, e i codici con trattino basso come en_US
vengono convertiti da e verso BCP 47 senza perdite en-US. Collega
onChange (o il valore associato) a i18next, Paraglide, vue-i18n o a ciò che usi.
text-size-picker — dimensione controllata dal lettore
Un guadagno di accessibilità che richiede minuti: l'helper imposta
data-text-size="{slug}" sulla radice del documento e il tuo CSS associa ogni valore a una dimensione.
<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%; }
Dimensiona il layout in rem e l'intera app si ridimensiona con la scelta dell'utente. Le etichette sono in maiuscolo iniziale a partire dagli slug ("X Large") o sostituite con sizeLabels.
Controlla il lavoro: scegli "Large" dal selettore e il testo della pagina cresce. Ricarica — è ancora grande: la scelta è stata salvata in
localStorage. Passa il selettore della lingua all'arabo e
dir="rtl" viene impostato automaticamente sul documento.
share-picker — invia questa pagina
Un pulsante a glifo singolo che apre il foglio di condivisione nativo del dispositivo dove esiste, e altrimenti ripiega su un elenco di destinazioni che fornisci, più un'azione per copiare l'URL. Non include URL di social network — quali reti appartengano al tuo prodotto è una tua scelta, non del design system.
<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 ha come valore predefinito location.hrefquindi il caso comune non richiede collegamenti. Forza un percorso con strategy="list" oppure
strategy="native" quando serve un comportamento coerente tra le piattaforme per test o schermate.
date-time-picker — una data, un'ora o entrambe
Un campo di testo in cui puoi scrivere, più un pulsante a icona che apre una finestra di selezione della data WAI-ARIA APG. Corretto per la lingua per costruzione — nomi dei mesi, nomi dei giorni, primo giorno della settimana e orologio a 12 o 24 ore provengono tutti da Intl — e il valore è sempre una stringa ISO ordinabile e senza fuso orario: "2026-03-15" per
mode="date", "09:30" per
mode="time", "2026-03-15T09:30" per
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",
}}
/>
Il valore ISO è identico a quello che invia <input type="date">
così puoi sostituire il controllo nativo senza toccare il tuo backend.
motion-picker — rispetta la riduzione del movimento
L'helper imposta data-motion="{slug}" sulla radice del documento. Il suo primo valore viene dall'impostazione
prefers-reduced-motion del sistema operativo del visitatore — sempre, senza opt-in, perché il movimento è un'esigenza reale di accessibilità (WCAG 2.3.3). Il tuo CSS e i tuoi script decidono cosa sopprimere.
<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 — una casella di ricerca che non si mette in mezzo
Un pulsante a icona che apre un campo di ricerca. Premere Invio, o il pulsante ⏎ accanto al campo, naviga con una semplice richiesta GET verso
/?<text> (il testo viene ripulito dagli spazi e codificato URI; una ricerca vuota non porta da nessuna parte). I suoi tre nomi accessibili sono obbligatori, perché l'helper non include inglese.
<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 cambia il percorso (/search?foo) e
navigate mantiene la navigazione dentro l'app; senza di esso l'helper chiama location.assign.
picker-bar — l'intera riga dell'intestazione in una volta
picker-bar rende ricerca, tema, lingua, dimensione del testo e condivisione in una riga, con il set completo di temi di riferimento e la scala del testo a sette gradini già collegati. Ogni nome accessibile arriva in un unico oggetto
labels obbligatorio.
<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}
/>
Raggiungi qualsiasi selettore avvolto con searchProps,
themeProps, localeProps,
textSizeProps e shareProps.
I tooltip sono integrati
Ogni selettore mostra la propria etichetta in un tooltip quando il puntatore si ferma sul suo pulsante o il pulsante ha il focus da tastiera. Il tooltip resta mentre il puntatore si sposta su di esso, Esc lo chiude ovunque sia il focus, e non compare mai mentre il popup del selettore è aperto. Porta lo stesso testo del nome accessibile del pulsante, quindi non c'è nulla da configurare né da tradurre due volte; i temi di riferimento lo stilizzano.
Un pannello di impostazioni in un unico posto
I quattro helper delle preferenze si compongono in modo naturale:
<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>
Verificato: gli snippet di locale-picker, text-size-picker, share-picker, date-time-picker e del pannello combinato sono stati compilati singolarmente rispetto ai 0.1.1 pacchetti pubblicati tramite
svelte/server (2026-08-29); gli snippet di motion-picker, search-picker e picker-bar sono stati renderizzati con i componenti dei pacchetti stessi il 2026-10-06.
Dove trovarli
# 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-
Ogni pacchetto ha il proprio spec, test mappati sulle clausole dello spec, esempi eseguibili (inclusi i pattern con cookie per SSR) e una pipeline di build + pubblicazione. I pacchetti Svelte sono canonici; nel dubbio, vincono i loro contratti.
Prossimi passi
- Catalogo dei componenti — il riferimento completo dei 571 componenti.
- Aiuto — risoluzione dei problemi e FAQ.
- Perché Lily — e come sostenere il progetto.
Domande lungo la strada? La pagina di aiuto è piena di risposte — e se un passo può essere più chiaro, faccelo sapere e miglioreremo volentieri il tutorial.