偏好设置辅助包

每种框架有七个小型包,每个包从头到尾负责一项用户任务,另有一个把其中五个组装起来个栏。侬已经见过 theme-picker;搿搭是 locale-picker、 text-size-picker 搭 motion-picker(偏好设置),share-picker 搭 search-picker(操作),date-time-picker(表单值),以及 picker-bar。

侬将构建啥

一个设置面板,用户可以在其中选择语言搭文字大小——搿眼选择作用于整个文档,在多次访问之间保持,而侬只需要两个组件搭几行 CSS。大约 15 分钟。

开始之前

请先完成侬所用技术栈个框架教程。下面个示例使用 Svelte;React、Vue、Angular、HTML、Nunjucks 搭 Blazor 个辅助包在契约上逐条一致。

伊拉共有个形态

  • 一个 headless 图标按钮,打开 WAI-ARIA APG 列表框(对于 date-time-picker 则是日期选择器对话框)——勿使用原生个 <select>,所以每种框架侪有完全相同个键盘行为搭样式钩子。
  • 每个包一个类名钩子(.locale-picker、.text-size-picker、.share-picker、.date-time-picker),勿附带任何 CSS。
  • SSR 安全:DOM 写入只发生在挂载/副作用生命周期中。
  • 国际化友好:每一条面向用户个字符串侪是 prop。
  • 提供 Svelte(规范版本)、React、Vue、Angular、HTML 自定义元素、Nunjucks 搭 Blazor 版本——每个版本个契约相同。

theme-picker、locale-picker 搭 text-size-picker 各自从头到尾负责一项用户偏好(选择、应用到 DOM、通过 storageKey prop 可选个 localStorage 持久化)。share-picker 搭 date-time-picker 则性质不同: share-picker 负责一个操作——伊勿对文档应用任何内容,也勿保存任何内容——而 date-time-picker 负责一个 表单值,因为表单中个日期是数据,而不是偏好。

locale-picker——语言与方向

让用户选择一种语言环境,然后把 lang 搭 dir 写到文档根元素上,让侬个国际化库、侬个 CSS 搭辅助技术侪跟着变化。阿拉伯语、希伯来语及其伊从右到左个文字会被自动检测为 RTL。伊只专注于发出信号——翻译由侬个国际化库负责。

<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 来设定布局尺寸,整个应用就会随用户个选择而缩放。标签由 slug 转为首字母大写形式 (“X Large”),或用 sizeLabels 覆盖。

检查侬个成果:在选择器中选择“Large”,页面文字就会变大。重新加载——伊仍然是大号:搿个选择已经保存到 localStorage。把语言选择器切换为阿拉伯语, dir="rtl" 会自动应用到文档上。

share-picker——分享搿个页面

一个单图标按钮,在设备有原生分享面板时打开伊,否则回退为侬提供个目标列表,外加一个复制网址个操作。伊勿附带任何社交网络个网址——侬个产品应该包含哪些网络,由侬决定,而不是由设计系统决定。

<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 字符串:mode="date" 时为 "2026-03-15",mode="time" 时为 "09:30", mode="datetime" 时为 "2026-03-15T09:30"。

<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——勿碍事个搜索框

一个打开搜索框个图标按钮。按下回车键,或字段旁边个 ⏎ 按钮,就会用一次普通个 GET 请求导航到 /?<text>(文本会去掉首尾空白并进行 URI 编码;空查询不会跳转到任何地方)。伊个三个可访问名称是必填个,因为辅助包勿附带英文。

<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 在一行中渲染搜索、主题、语言、文字大小搭分享,并预先接好了全套参考主题搭七级文字大小比例。所有可访问名称侪通过一个必填个 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 侪会将其关闭,而且在选择器个弹出层打开时伊从勿显示。伊个文字与按钮个可访问名称相同,所以无需配置,也勿必翻译两遍;参考主题已经为伊设置了样式。

把设置面板集中在一处

这四个偏好设置辅助包可以自然地组合在一起:

<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 以及组合面板个代码片段,已于 2026-08-29 针对已发布个 0.1.1 包,经 svelte/server 逐个编译通过;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 cookie 模式),以及构建与发布流水线。Svelte 版本是规范版本;有疑问时,以伊拉个契约为准。

下一步

过程中有疑问?帮助页面里有大量解答——如果某一步可以写得更清楚, 请告诉阿拉,阿拉老乐意改进教程。