Trợ giúp tùy chọn
Bảy gói nhỏ cho mỗi framework, mỗi gói lo trọn một việc của người dùng, cộng với một thanh gom năm gói trong số đó. Bạn đã biết theme-picker; đây là locale-picker, text-size-picker và motion-picker (tùy chọn), share-picker và search-picker (hành động), date-time-picker (giá trị biểu mẫu), và picker-bar.
Bạn sẽ xây dựng gì
Một bảng cài đặt nơi người dùng chọn ngôn ngữ và cỡ chữ — các lựa chọn áp dụng cho toàn tài liệu, được giữ lại giữa các lần truy cập, và chỉ tốn hai thành phần cùng vài dòng CSS. Khoảng 15 phút.
Trước khi bắt đầu
Hãy hoàn thành hướng dẫn framework cho bộ công nghệ của bạn. Các ví dụ dưới đây dùng Svelte; các trợ giúp React, Vue, Angular, HTML, Nunjucks và Blazor khớp từng hợp đồng một.
Hình dạng chung
- Một nút biểu tượng headless mở listbox theo WAI-ARIA APG (hoặc, với date-time-picker, một hộp thoại chọn ngày) — không dùng
<select>gốc, nên mọi framework đều có cùng hành vi bàn phím và class hook kiểu dáng. - Một class hook cho mỗi gói (
.locale-picker,.text-size-picker,.share-picker,.date-time-picker), không đi kèm CSS. - An toàn với SSR: việc ghi DOM chỉ xảy ra trong vòng đời mount/effect.
- Thân thiện với i18n: mọi chuỗi người dùng nhìn thấy đều là thuộc tính.
- Có cho Svelte (chuẩn), React, Vue, Angular, phần tử tùy chỉnh HTML, Nunjucks và Blazor — cùng một hợp đồng ở mỗi nơi.
theme-picker, locale-picker và text-size-picker mỗi cái lo trọn một
tùy chọn của người dùng (lựa chọn, áp dụng vào DOM,
localStorage lưu trữ tùy chọn qua thuộc tính storageKey
). share-picker và date-time-picker khác về bản chất: share-picker lo một hành động — nó không áp dụng gì vào tài liệu và không lưu gì — còn date-time-picker lo một
giá trị biểu mẫu, vì một ngày trong biểu mẫu là dữ liệu chứ không phải tùy chọn.
locale-picker — ngôn ngữ và hướng viết
Cho phép người dùng chọn ngôn ngữ-khu vực, rồi ghi lang và
dir vào gốc tài liệu để thư viện i18n, CSS và công nghệ hỗ trợ đều theo đó. RTL được tự động phát hiện cho tiếng Ả Rập, tiếng Do Thái và các chữ viết từ phải sang trái khác. Nó chỉ làm nhiệm vụ báo hiệu — thư viện i18n của bạn lo việc dịch.
<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"
/>
Nhãn tùy chọn lấy từ bảng tên ngôn ngữ-khu vực có sẵn (có thể ghi đè qua localeLabels), mỗi tùy chọn mang thuộc tính
lang riêng để trình đọc màn hình phát âm "Français" bằng tiếng Pháp, và mã dùng dấu gạch dưới như en_US
chuyển đổi qua lại với BCP 47 không mất dữ liệu en-US. Nối
onChange (hoặc giá trị được liên kết) vào i18next, Paraglide, vue-i18n hoặc bất cứ thứ gì bạn dùng.
text-size-picker — cỡ chữ do người đọc điều khiển
Một chiến thắng về khả năng tiếp cận chỉ mất vài phút: trợ giúp đặt
data-text-size="{slug}" trên gốc tài liệu và CSS của bạn ánh xạ mỗi giá trị sang kích thước.
<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%; }
Đặt kích thước bố cục bằng rem và toàn bộ ứng dụng co giãn theo lựa chọn của người dùng. Nhãn được viết hoa chữ cái đầu từ slug ("X Large") hoặc ghi đè bằng sizeLabels.
Kiểm tra kết quả: chọn "Large" từ bộ chọn, và chữ trên trang to ra. Tải lại — vẫn to: lựa chọn đã được lưu vào
localStorage. Chuyển bộ chọn ngôn ngữ sang tiếng Ả Rập và
dir="rtl" được đặt lên tài liệu tự động.
share-picker — gửi trang này
Một nút một ký hiệu mở bảng chia sẻ gốc của thiết bị nếu có, và nếu không thì chuyển sang danh sách đích do bạn cung cấp, cùng hành động sao chép URL. Nó không kèm URL mạng xã hội nào — mạng nào phù hợp với sản phẩm của bạn là quyết định của bạn, không phải của hệ thống thiết kế.
<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 mặc định là location.hrefnên trường hợp thông thường không cần nối dây gì. Buộc một đường dẫn bằng strategy="list" hoặc
strategy="native" khi bạn cần hành vi nhất quán giữa các nền tảng để kiểm thử hoặc chụp ảnh màn hình.
date-time-picker — một ngày, một giờ, hoặc cả hai
Một ô văn bản bạn có thể gõ vào, cùng nút biểu tượng mở hộp thoại chọn ngày theo WAI-ARIA APG. Đúng theo ngôn ngữ-khu vực từ cấu trúc — tên tháng, tên thứ, ngày đầu tuần và đồng hồ 12 hay 24 giờ đều lấy từ Intl — và giá trị luôn là chuỗi ISO sắp xếp được và không có múi giờ: "2026-03-15" cho
mode="date", "09:30" cho
mode="time", "2026-03-15T09:30" cho
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",
}}
/>
Giá trị ISO giống hệt những gì <input type="date">
gửi đi, nên bạn có thể thay điều khiển gốc vào hay ra mà không đụng đến backend.
motion-picker — tôn trọng giảm chuyển động
Trợ giúp đặt data-motion="{slug}" trên gốc tài liệu. Giá trị đầu tiên lấy từ cài đặt
prefers-reduced-motion của hệ điều hành người truy cập — luôn luôn, không cần cờ bật, vì chuyển động là một nhu cầu tiếp cận thật sự (WCAG 2.3.3). CSS và tập lệnh của bạn quyết định cái gì bị chặn.
<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 — ô tìm kiếm không chiếm chỗ
Một nút biểu tượng mở trường tìm kiếm. Nhấn Return, hoặc nút ⏎ bên cạnh trường, sẽ điều hướng bằng một yêu cầu GET thường đến
/?<text> (văn bản được cắt khoảng trắng và mã hóa URI; truy vấn rỗng không đi đâu cả). Ba tên có thể tiếp cận của nó là bắt buộc, vì trợ giúp không kèm tiếng Anh.
<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 thay đổi đường dẫn (/search?foo), và
navigate giữ việc điều hướng trong ứng dụng; nếu không có thì trợ giúp gọi location.assign.
picker-bar — cả hàng đầu trang cùng lúc
picker-bar hiển thị tìm kiếm, chủ đề, ngôn ngữ, cỡ chữ và chia sẻ trên một hàng, với bộ chủ đề tham chiếu đầy đủ và thang cỡ chữ bảy bậc được nối sẵn. Mọi tên có thể tiếp cận đến trong một đối tượng
labels bắt buộc.
<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}
/>
Truy cập bất kỳ bộ chọn nào được bọc bằng searchProps,
themeProps, localeProps,
textSizeProps và shareProps.
Chú giải công cụ có sẵn
Mỗi bộ chọn hiển thị nhãn của nó trong chú giải công cụ khi con trỏ dừng trên nút hoặc nút có tiêu điểm bàn phím. Chú giải vẫn hiện khi con trỏ di chuyển lên nó, Escape đóng nó dù tiêu điểm ở đâu, và nó không bao giờ hiện khi cửa sổ bật lên của bộ chọn đang mở. Nó mang cùng văn bản với tên có thể tiếp cận của nút, nên không có gì phải cấu hình và không phải dịch hai lần; các chủ đề tham chiếu tạo kiểu cho nó.
Một bảng cài đặt ở một chỗ
Bốn trợ giúp tùy chọn kết hợp với nhau một cách tự nhiên:
<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>
Đã xác minh: các đoạn mã locale-picker, text-size-picker, share-picker, date-time-picker và bảng kết hợp được biên dịch riêng lẻ với các 0.1.1 gói đã xuất bản thông qua
svelte/server (2026-08-29); các đoạn mã motion-picker, search-picker và picker-bar được hiển thị bằng chính các thành phần của gói vào ngày 2026-10-06.
Lấy ở đâu
# 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-
Mỗi gói có spec riêng, các bài kiểm thử gắn với điều khoản của spec, ví dụ chạy được (gồm cả mẫu cookie cho SSR) và quy trình build + xuất bản. Các gói Svelte là chuẩn; khi nghi ngờ, hợp đồng của chúng được ưu tiên.
Các bước tiếp theo
- Danh mục thành phần — tài liệu tham chiếu đầy đủ của 571 thành phần.
- Trợ giúp — khắc phục sự cố và câu hỏi thường gặp.
- Vì sao chọn Lily — và cách ủng hộ dự án.
Có thắc mắc trên đường đi? Trang trợ giúp có đầy câu trả lời — và nếu một bước có thể rõ ràng hơn, hãy cho chúng tôi biết và chúng tôi sẽ vui lòng cải thiện hướng dẫn.