Inställningshjälpare

Sju små paket per ramverk, vart och ett äger en användaruppgift från början till slut, plus ett fält som sätter ihop fem av dem. Du har redan träffat theme-picker; här är locale-picker, text-size-picker och motion-picker (inställningar), share-picker och search-picker (handlingar), date-time-picker (ett formulärvärde) och picker-bar.

Det här bygger du

En inställningspanel där användare väljer språk och textstorlek — val som gäller hela dokumentet, består mellan besök och kostar dig två komponenter och några rader CSS. Ungefär 15 minuter.

Innan du börjar

Gör klart ramverkshandledningen för din stack först. Exemplen nedan är Svelte; hjälparna för React, Vue, Angular, HTML, Nunjucks och Blazor motsvarar dem kontrakt för kontrakt.

Formen de delar

  • En headless-ikonknapp som öppnar en WAI-ARIA APG-listbox (eller, för date-time-picker, en datumväljardialog) — ingen inbyggd <select>, så varje ramverk får samma tangentbordsbeteende och stylingkrokar.
  • En klasskrok per paket (.locale-picker, .text-size-picker, .share-picker, .date-time-picker), noll CSS levereras.
  • SSR-säker: DOM-skrivningar sker bara i mount-/effect-livscykeln.
  • i18n-rent: varje sträng som användaren ser är en prop.
  • Finns för Svelte (kanonisk), React, Vue, Angular, HTML-anpassat element, Nunjucks och Blazor — samma kontrakt i vart och ett.

theme-picker, locale-picker och text-size-picker äger var och en en användar inställning från början till slut (val, tillämpning på DOM, valfri localStorage beständighet via storageKey -propen). share-picker och date-time-picker är annorlunda till sin art: share-picker äger en handling — den tillämpar inget på dokumentet och sparar inget — och date-time-picker äger ett formulärvärde, eftersom ett datum i ett formulär är data, inte en inställning.

locale-picker — språk och riktning

Låter användaren välja ett språkområde och skriver sedan lang och dir på dokumentroten så att ditt i18n-bibliotek, din CSS och hjälpmedel alla följer med. RTL identifieras automatiskt för arabiska, hebreiska och andra skriftsystem som skrivs från höger till vänster. Den ägnar sig enbart åt att signalera — ditt i18n-bibliotek sköter översättningen.

<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"
/>

Alternativen får sina etiketter från en inbyggd tabell med språkområdesnamn (kan åsidosättas via localeLabels), varje alternativ bär sitt eget lang -attribut så att skärmläsare uttalar "Français" på franska, och koder med understreck som en_US konverteras förlustfritt till och från BCP 47 en-US. Koppla onChange (eller det bundna värdet) till i18next, Paraglide, vue-i18n eller vad du än använder.

text-size-picker — storlek som läsaren styr

En tillgänglighetsvinst som tar minuter: hjälparen sätter data-text-size="{slug}" på dokumentroten och din CSS kopplar varje värde till en storlek.

<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%; }

Dimensionera din layout i rem så skalas hela appen med användarens val. Etiketterna får versal begynnelsebokstav från sluggarna ("X Large") eller åsidosätts med sizeLabels.

Kontrollera ditt arbete: välj "Large" i väljaren, så växer sidtexten. Ladda om — den är fortfarande stor: valet sparades i localStorage. Byt språkväljaren till arabiska så sätts dir="rtl" automatiskt på dokumentet.

share-picker — skicka den här sidan

En knapp med en enda symbol som öppnar enhetens inbyggda delningsblad där ett finns, och annars faller tillbaka på en lista med mål som du anger, plus en åtgärd för att kopiera URL:en. Den levererar inga URL:er till sociala nätverk — vilka nätverk som hör hemma i din produkt är ditt val, inte designsystemets.

<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 har som standard location.href, så det vanliga fallet behöver ingen koppling. Tvinga fram en väg med strategy="list" eller strategy="native" när du behöver konsekvent beteende över plattformar för tester eller skärmdumpar.

date-time-picker — ett datum, en tid eller båda

Ett textfält du kan skriva i, plus en ikonknapp som öppnar en WAI-ARIA APG-datumväljardialog. Språkriktig genom konstruktion — månadsnamn, veckodagsnamn, första veckodag och 12- eller 24-timmarsklocka kommer alla från Intl — och värdet är alltid en sorterbar ISO-sträng utan tidszon: "2026-03-15" för mode="date", "09:30" för mode="time", "2026-03-15T09:30" för 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",
  }}
/>

ISO-värdet är identiskt med det som <input type="date"> skickar, så du kan byta in eller ut den inbyggda kontrollen utan att röra din backend.

motion-picker — respektera minskad rörelse

Hjälparen sätter data-motion="{slug}" på dokumentroten. Dess första värde kommer från besökarens operativsystems prefers-reduced-motion -inställning — alltid, utan opt-in-flagga, eftersom rörelse är ett verkligt tillgänglighetsbehov (WCAG 2.3.3). Din CSS och dina skript avgör vad som undertrycks.

<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 — en sökruta som inte är i vägen

En ikonknapp som öppnar ett sökfält. Att trycka på Retur, eller på ⏎-knappen vid fältet, navigerar med en vanlig GET-begäran till /?<text> (texten trimmas och URI-kodas; en tom fråga leder ingenstans). Dess tre tillgängliga namn är obligatoriska, eftersom hjälparen inte levererar någon engelska.

<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 ändrar sökvägen (/search?foo), och navigate håller navigeringen inne i appen; utan den anropar hjälparen location.assign.

picker-bar — hela rubrikraden på en gång

picker-bar renderar sök, tema, språk, textstorlek och delning på en rad, med hela uppsättningen referensteman och den sjustegiga textskalan förkopplade. Varje tillgängligt namn kommer i ett enda obligatoriskt labels -objekt.

<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}
/>

Nå vilken inbäddad väljare som helst med searchProps, themeProps, localeProps, textSizeProps och shareProps.

Verktygstips ingår

Varje väljare visar sin etikett i ett verktygstips när pekaren vilar på dess knapp eller knappen har tangentbordsfokus. Verktygstipset blir kvar medan pekaren flyttas till det, Escape stänger det oavsett var fokus är, och det visas aldrig medan väljarens popup är öppen. Det bär samma text som knappens tillgängliga namn, så det finns inget att konfigurera och inget att översätta två gånger; referenstemana formger det.

En inställningspanel på ett ställe

De fyra inställningshjälparna kombineras naturligt:

<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>

Verifierat: kodavsnitten för locale-picker, text-size-picker, share-picker, date-time-picker och den kombinerade panelen kompilerades var för sig mot de publicerade 0.1.1 -paketen, via svelte/server (2026-08-29); kodavsnitten för motion-picker, search-picker och picker-bar renderades mot paketens egna komponenter den 2026-10-06.

Var du får tag på dem

# 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-

Varje paket har sin egen spec, tester kopplade till specens klausuler, körbara exempel (inklusive SSR-cookiemönster) och en bygg- och publiceringspipeline. Svelte-paketen är kanoniska; vid tvekan gäller deras kontrakt.

Nästa steg

Frågor på vägen? Hjälpsidan är full av svar — och om ett steg kan bli tydligare, berätta för oss så förbättrar vi gärna handledningen.