Pembantu preferensi

Tujuh paket kecil per kerangka kerja, masing-masing memiliki satu tugas pengguna dari awal sampai akhir, ditambah bilah yang menggabungkan lima di antaranya. Anda sudah mengenal theme-picker; ini dia locale-picker, text-size-picker, dan motion-picker (preferensi), share-picker dan search-picker (tindakan), date-time-picker (nilai formulir), dan picker-bar.

Apa yang akan Anda bangun

Panel pengaturan tempat pengguna memilih bahasa dan ukuran teks — pilihan yang berlaku untuk seluruh dokumen, bertahan antarkunjungan, dan hanya memerlukan dua komponen serta beberapa baris CSS. Sekitar 15 menit.

Sebelum memulai

Selesaikan dulu tutorial kerangka kerja untuk tumpukan Anda. Contoh di bawah menggunakan Svelte; pembantu React, Vue, Angular, HTML, Nunjucks, dan Blazor sesuai kontrak demi kontrak.

Bentuk yang mereka bagi

  • Tombol ikon headless yang membuka kotak daftar WAI-ARIA APG (atau, untuk date-time-picker, dialog pemilih tanggal) — tanpa <select>bawaan, sehingga setiap kerangka kerja mendapat perilaku papan ketik dan kait gaya yang sama.
  • Satu kait kelas per paket (.locale-picker, .text-size-picker, .share-picker, .date-time-picker), nol CSS yang dikirim.
  • Aman untuk SSR: penulisan DOM hanya terjadi dalam siklus hidup mount/effect.
  • Bersih untuk i18n: setiap string yang dilihat pengguna adalah prop.
  • Tersedia untuk Svelte (kanonis), React, Vue, Angular, elemen kustom HTML, Nunjucks, dan Blazor — kontrak yang sama di masing-masing.

theme-picker, locale-picker, dan text-size-picker masing-masing memiliki satu preferensi pengguna dari awal sampai akhir (pemilihan, penerapan ke DOM, localStorage persistensi opsional melalui prop storageKey ). share-picker dan date-time-picker berbeda jenisnya: share-picker memiliki sebuah tindakan — tidak menerapkan apa pun ke dokumen dan tidak menyimpan apa pun — dan date-time-picker memiliki sebuah nilai formulir, karena tanggal dalam formulir adalah data, bukan preferensi.

locale-picker — bahasa dan arah

Membiarkan pengguna memilih lokal, lalu menulis lang dan dir ke akar dokumen sehingga pustaka i18n, CSS, dan teknologi bantu Anda semuanya mengikuti. RTL dideteksi otomatis untuk Arab, Ibrani, dan aksara lain dari kanan ke kiri. Ia hanya berfokus pada pemberian sinyal — pustaka i18n Anda yang menangani terjemahan.

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

Opsi diberi label dari tabel nama lokal bawaan (dapat ditimpa melalui localeLabels), setiap opsi membawa atribut lang sendiri sehingga pembaca layar melafalkan "Français" dalam bahasa Prancis, dan kode bergaris bawah seperti en_US dikonversi tanpa kehilangan ke BCP 47 dan kembali en-US. Hubungkan onChange (atau nilai terikat) ke i18next, Paraglide, vue-i18n, atau apa pun yang Anda gunakan.

text-size-picker — ukuran yang dikendalikan pembaca

Kemenangan aksesibilitas yang hanya butuh beberapa menit: pembantu menetapkan data-text-size="{slug}" pada akar dokumen dan CSS Anda memetakan setiap nilai ke ukuran.

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

Ukur tata letak Anda dalam rem dan seluruh aplikasi menyesuaikan dengan pilihan pengguna. Label dibentuk dari slug dengan huruf kapital awal ("X Large") atau ditimpa dengan sizeLabels.

Periksa pekerjaan Anda: pilih "Large" dari pemilih, dan teks halaman membesar. Muat ulang — masih besar: pilihan disimpan di localStorage. Ganti pemilih bahasa Anda ke Arab dan dir="rtl" ditetapkan pada dokumen secara otomatis.

share-picker — kirim halaman ini

Tombol satu glif yang membuka lembar berbagi bawaan perangkat jika ada, dan jika tidak, beralih ke daftar tujuan yang Anda sediakan, ditambah tindakan menyalin URL. Ia tidak menyertakan URL jejaring sosial apa pun — jejaring mana yang cocok untuk produk Anda adalah keputusan Anda, bukan keputusan sistem desain.

<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 bawaannya adalah location.hrefsehingga kasus umum tidak memerlukan pengkabelan. Paksa jalur dengan strategy="list" atau strategy="native" saat Anda memerlukan perilaku konsisten di berbagai platform untuk pengujian atau tangkapan layar.

date-time-picker — tanggal, waktu, atau keduanya

Kolom teks yang dapat Anda ketik, ditambah tombol ikon yang membuka dialog pemilih tanggal WAI-ARIA APG. Benar untuk lokal sejak rancangan — nama bulan, nama hari, hari pertama minggu, dan jam 12 atau 24 jam semuanya berasal dari Intl — dan nilainya selalu string ISO yang dapat diurutkan dan tanpa zona waktu: "2026-03-15" untuk mode="date", "09:30" untuk mode="time", "2026-03-15T09:30" untuk 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",
  }}
/>

Nilai ISO identik dengan yang dikirim <input type="date"> sehingga Anda dapat menukar kontrol bawaan masuk atau keluar tanpa menyentuh backend Anda.

motion-picker — hormati gerakan yang dikurangi

Pembantu menetapkan data-motion="{slug}" pada akar dokumen. Nilai pertamanya berasal dari pengaturan prefers-reduced-motion sistem operasi pengunjung — selalu, tanpa bendera opt-in, karena gerakan adalah kebutuhan aksesibilitas yang nyata (WCAG 2.3.3). CSS dan skrip Anda yang memutuskan apa yang ditekan.

<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 — kotak pencarian yang tidak menghalangi

Tombol ikon yang membuka kolom pencarian. Menekan Return, atau tombol ⏎ di samping kolom, bernavigasi dengan permintaan GET biasa ke /?<text> (teks dipangkas dan dikodekan URI; kueri kosong tidak menuju ke mana pun). Ketiga nama yang dapat diakses wajib diisi, karena pembantu tidak menyertakan bahasa Inggris.

<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 mengubah jalur (/search?foo), dan navigate menjaga navigasi tetap di dalam aplikasi; tanpanya pembantu memanggil location.assign.

picker-bar — seluruh baris header sekaligus

picker-bar merender pencarian, tema, lokal, ukuran teks, dan berbagi dalam satu baris, dengan set lengkap tema rujukan dan skala teks tujuh tingkat yang sudah terhubung. Setiap nama yang dapat diakses tiba dalam satu objek labels yang wajib.

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

Jangkau pemilih apa pun yang dibungkus dengan searchProps, themeProps, localeProps, textSizeProps dan shareProps.

Tooltip sudah bawaan

Setiap pemilih menampilkan labelnya dalam tooltip ketika penunjuk berhenti di tombolnya atau tombol memiliki fokus papan ketik. Tooltip bertahan saat penunjuk bergerak ke atasnya, Escape menutupnya di mana pun fokus berada, dan tidak pernah tampil selagi popup pemilih terbuka. Ia membawa teks yang sama dengan nama yang dapat diakses tombol, jadi tidak ada yang perlu dikonfigurasi atau diterjemahkan dua kali; tema rujukan memberinya gaya.

Panel pengaturan di satu tempat

Keempat pembantu preferensi tersusun secara alami:

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

Diverifikasi: cuplikan locale-picker, text-size-picker, share-picker, date-time-picker, dan panel gabungan dikompilasi satu per satu terhadap paket 0.1.1 yang diterbitkan, melalui svelte/server (2026-08-29); cuplikan motion-picker, search-picker, dan picker-bar dirender terhadap komponen paket itu sendiri pada 2026-10-06.

Di mana mendapatkannya

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

Setiap paket memiliki spec sendiri, pengujian yang dipetakan ke klausa spec, contoh yang dapat dijalankan (termasuk pola cookie SSR), dan jalur pipa build + penerbitan. Paket Svelte bersifat kanonis; jika ragu, kontrak merekalah yang menang.

Langkah berikutnya

Ada pertanyaan di tengah jalan? Halaman bantuan penuh jawaban — dan jika suatu langkah bisa lebih jelas, beri tahu kami dan kami dengan senang hati akan memperbaiki tutorial ini.