設定ヘルパー

各フレームワークに 7 つの小さなパッケージがあり、それぞれが 1 つのユーザーの用途を最初から最後まで受け持ちます。さらに、そのうち 5 つをまとめるバーもあります。すでに theme-pickerは紹介しました。ここでは locale-picker、text-size-picker、motion-picker(設定)、share-picker、search-picker(アクション)、date-time-picker(フォームの値)、そして picker-bar を扱います。

作るもの

ユーザーが言語とテキストサイズを選べる設定パネル — 選択はドキュメント全体に適用され、訪問をまたいで保持され、必要なのは 2 つのコンポーネントと数行の CSS だけです。所要時間は約 15 分です。

始める前に

先に、お使いのスタックの フレームワークチュートリアル を終えてください。以下のサンプルは Svelte ですが、React、Vue、Angular、HTML、Nunjucks、Blazor のヘルパーも、契約ごとに同じ内容になっています。

共通する形

  • WAI-ARIA APG のリストボックス(date-time-picker の場合は日付選択ダイアログ)を開くヘッドレスのアイコンボタンです — ネイティブの <select>は使わないので、どのフレームワークでも同じキーボード操作とスタイルフックになります。
  • パッケージごとに 1 つのクラスフック(.locale-picker, .text-size-picker, .share-picker, .date-time-picker)で、CSS は一切同梱しません。
  • SSR 対応: DOM への書き込みはマウント/エフェクトのライフサイクル内だけで行われます。
  • i18n に対応: ユーザーに見える文字列はすべてプロパティです。
  • Svelte(基準実装)、React、Vue、Angular、HTML カスタム要素、Nunjucks、Blazor で利用でき、どれも同じ契約です。

theme-picker、locale-picker、text-size-picker は、それぞれ 1 つのユーザー 設定 を最初から最後まで(選択、DOM への適用、任意の localStorage 永続化を storageKey プロパティ経由で)受け持ちます。share-picker と date-time-picker は種類が異なります。share-picker は アクション を受け持ち — ドキュメントには何も適用せず、何も保持しません — date-time-picker は フォームの値を受け持ちます。フォーム内の日付は設定ではなくデータだからです。

locale-picker — 言語と文字方向

ユーザーにロケールを選ばせ、 lang と dir をドキュメントのルートに書き込みます。これにより、i18n ライブラリ、CSS、支援技術のすべてが追従します。アラビア語やヘブライ語などの右から左の文字は自動的に検出されます。役割はあくまで通知であり、翻訳は 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"
/>

選択肢のラベルは組み込みのロケール名の表から付けられ( localeLabelsで上書きできます)、各選択肢は自前の lang 属性を持つので、スクリーンリーダーは「Français」をフランス語で発音します。また、次のようなアンダースコア形式のコードは、 en_US BCP 47 へ損失なく往復変換されます en-US。 onChange (またはバインドされた値)を i18next、Paraglide、vue-i18n など、お使いのものに接続してください。

text-size-picker — 読む人が操作できるサイズ

数分でできるアクセシビリティの改善です。このヘルパーはドキュメントのルートに data-text-size="{slug}" を設定し、CSS が各値をサイズに対応付けます。

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

レイアウトを rem で組めば、アプリ全体がユーザーの選択に合わせて拡大縮小します。ラベルはスラッグからタイトルケースで作られます(「X Large」)。 sizeLabels.

動作の確認: で上書きもできます。ピッカーから「Large」を選ぶと、ページのテキストが大きくなります。再読み込みしても大きいままです — 選択が次に保存されたからです: localStorage。言語ピッカーをアラビア語に切り替えると、 dir="rtl" が自動的にドキュメントに設定されます。

share-picker — このページを送る

1 文字のボタンで、利用できる環境ではデバイスのネイティブな共有シートを開き、そうでなければ、あなたが用意した送信先の一覧とURL のコピー操作に切り替わります。ソーシャルネットワークの URL は同梱しません — どのネットワークが自社の製品にふさわしいかは、デザインシステムではなくあなたが決めることだからです。

<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 の既定値は location.hrefなので、一般的な場合は配線が不要です。テストやスクリーンショットで、プラットフォームをまたいで一貫した動作が必要なときは、 strategy="list" または strategy="native" で経路を強制できます。

date-time-picker — 日付、時刻、またはその両方

入力できるテキストフィールドと、WAI-ARIA APG の日付選択ダイアログを開くアイコンボタンです。ロケールに合わせて作られており — 月名、曜日名、週の開始日、12 時間制か 24 時間制かはすべて Intl から決まり — 値は常に、並べ替え可能でタイムゾーンを含まない ISO 文字列です: "2026-03-15" は mode="date", "09:30" は mode="time", "2026-03-15T09:30" は 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 の値は、次が送信する値と同じです: <input type="date"> なので、バックエンドに手を加えずにネイティブのコントロールと入れ替えられます。

motion-picker — 視覚効果の軽減を尊重する

このヘルパーはドキュメントのルートに data-motion="{slug}" を設定します。最初の値は訪問者のオペレーティングシステムの prefers-reduced-motion 設定から取得します — 常に、有効化のフラグなしで行います。動きの多さは実際のアクセシビリティ上の必要性(WCAG 2.3.3)だからです。何を抑えるかは、CSS とスクリプトが決めます。

<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 — 邪魔にならない検索ボックス

検索フィールドを開くアイコンボタンです。Return キーか、フィールド横の ⏎ ボタンを押すと、プレーンな GET リクエストで次へ移動します: /?<text> (テキストは前後の空白を除き URI エンコードされ、空のクエリでは何も起きません)。アクセシブルな名前は 3 つとも必須です。このヘルパーには英語が同梱されていないからです。

<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 はパスを変更し(/search?foo)、 navigate はナビゲーションをアプリ内に留めます。これがない場合、ヘルパーは次を呼び出します: location.assign.

picker-bar — ヘッダー行をまるごと

picker-bar 検索、テーマ、ロケール、テキストサイズ、共有を 1 行で描画し、参照テーマの全セットと 7 段階のテキストスケールがあらかじめ組み込まれています。アクセシブルな名前はすべて、必須の 1 つの labels オブジェクトで渡します。

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

内包されたピッカーには、次でアクセスできます: searchProps, themeProps, localeProps, textSizeProps と shareProps.

ツールチップは標準装備

各ピッカーは、ポインターがボタンの上にあるとき、またはボタンにキーボードフォーカスがあるときに、ラベルをツールチップで表示します。ポインターがツールチップに移ってもそのまま表示され、フォーカスがどこにあっても Escape で閉じられ、ピッカーのポップアップが開いている間は表示されません。ボタンのアクセシブルな名前と同じテキストを使うので、設定するものも、二度翻訳するものもありません。スタイルは参照テーマが付けます。

設定パネルを 1 か所に

4 つの設定ヘルパーは自然に組み合わせられます:

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

確認済み: locale-picker、text-size-picker、share-picker、date-time-picker、およびまとめたパネルのスニペットは、公開済みの 0.1.1 パッケージに対して、個別にコンパイルして確認しました。次を通して: svelte/server (2026-08-29)。motion-picker、search-picker、picker-bar のスニペットは、2026-10-06 にパッケージ自身のコンポーネントで描画して確認しました。

入手先

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

各パッケージには、専用の仕様、仕様の条項に対応したテスト、実行できるサンプル(SSR のクッキーのパターンを含む)、ビルドと公開のパイプラインがあります。Svelte のパッケージが基準で、迷ったときはその契約が優先されます。

次のステップ

途中で疑問があれば、 ヘルプページ に答えがたくさんあります。もし手順がもっと分かりやすくできるなら、 お知らせください 。喜んでチュートリアルを改善します。