Lily 入门

选择一个框架,克隆 headless 仓库或示例应用,然后开始组合你自己的页面。喜欢有引导的路径?请从教程开始。

安装

Lily 针对每个框架以独立的 Git 仓库形式发布。最快的试用方法是克隆你所用技术栈的 headless 仓库:

git clone https://github.com/LilyDesignSystem/lily-design-system-react-headless
cd lily-design-system-react-headless
pnpm install

同样的模式也适用于其他框架:

  • @lilydesignsystem/html-headless — 无需安装;复制 .html 文件即可
  • @lilydesignsystem/svelte-headless — pnpm install
  • @lilydesignsystem/react-headless — pnpm install
  • @lilydesignsystem/vue-headless — pnpm install
  • @lilydesignsystem/angular-headless — pnpm install
  • @lilydesignsystem/nunjucks-headless — pnpm install
  • lily-design-system-blazor-headless — dotnet build

headless 库的设计目的是被克隆或直接纳入你的项目——把源代码当作事实来源,需要什么就复制什么。偏好辅助组件还以可安装软件包的形式提供,并有构建与发布流水线(JS 框架用 npm,Blazor 用 NuGet)。

使用 headless 组件

headless 组件自带语义化 HTML、ARIA 和属性——但没有 CSS。下面是各框架中的一个按钮:

HTML

<button class="button" type="button" aria-label="Save">
  Save
</button>

Svelte

<script>
  import Button from "lily-design-system-svelte-headless/components/Button/Button.svelte";
</script>

<Button onclick={save}>Save</Button>

React

import Button from "lily-design-system-react-headless/components/Button";

<Button onClick={save}>Save</Button>

Vue

<script setup>
  import Button from "lily-design-system-vue-headless/components/Button.vue";
</script>

<Button @click="save">Save</Button>

Angular

import { Button } from "@lilydesignsystem/angular-headless";

@Component({
  imports: [Button],
  template: `<lily-button (click)="save()">Save</lily-button>`,
})

Blazor

<Button OnClick="Save">Save</Button>

Nunjucks

{% from "components/button/macro.njk" import button %}

{{ button({ text: "Save", type: "button" }) }}

使用带样式的示例

示例应用包含 CSS、路由和完整的演示页面。最快的实验方式是启动 SvelteKit、Next、Nuxt、Analog 或 Eleventy 示例应用,并在 /components 查看演示。

git clone https://github.com/LilyDesignSystem/lily-design-system-svelte-sveltekit-examples
cd lily-design-system-svelte-sveltekit-examples
pnpm install
pnpm run dev

然后打开 http://localhost:5173 并浏览 /components。

样式与设计令牌

每个组件在其根元素上渲染一个 kebab-case 类。例如,<Button> 会渲染 <button class="button">。你想怎么设置样式都行:

.button {
  background: var(--my-primary);
  color: #fff;
  padding: 0.75rem 1.5rem;
  border-radius: 0.5rem;
}
.button:hover { background: var(--my-primary-hover); }

Lily 默认的调色板(用于示例应用)是:

  • 主色:#2563eb
  • 危险:#dc2626
  • 警告:#f59e0b
  • 成功:#16a34a
  • 页面背景:#f9fafb
  • 卡片背景:#ffffff

这些只是建议,不是要求。换成你自己品牌的调色板,Lily 会欣然配合。

现成主题

不想从零开始写 CSS?Lily 附带 45 个独立的参考主题,位于 themes/ 目录中。每一个都是针对 Lily 类钩子的一份样式表——链接它,样式就生效了:

<link rel="stylesheet" href="/assets/themes/united-kingdom-government-digital-service.css" />

这一组主题涵盖:

  • 公共部门 — NHS England、NHS Scotland 和 NHS Wales(各有面向患者和面向从业者的版本)、GOV.UK GDS,以及美国网页设计系统。
  • 受厂商启发 — Adobe Spectrum、Mozilla Protocol。
  • 通用 — 浅色、深色、nord、dracula、wireframe,以及三十多个其他主题。

主题选择器使用 :where(...),所以在优先级上你自己的 CSS 总是胜出。把它们与下面的 theme-picker 辅助组件搭配即可在运行时切换,或参阅主题教程。

偏好辅助组件

每个框架都有一个配套的 *-helpers 目录,其中有八个小型选择器(以及一个把它们组装在一起的 picker-bar)。每个都是打开弹出层的 headless 图标按钮——选项列表、链接列表、搜索表单,或(对 date-time-picker 而言)日期选择对话框——而不是原生的 <select>;它对 SSR 安全,也不附带任何 CSS:

  • theme-picker — 通过替换一个受管理的 <link> 在运行时加载主题样式表,在文档上设置 data-theme,并可选择持久化到 localStorage。
  • locale-picker — 设置 lang 和 dir(自动检测从右到左),以便你的 i18n 库跟随;它自己不做任何翻译。
  • text-size-picker — 在文档上设置 data-text-size;你的 CSS 把每个值映射为字体大小。
  • motion-picker — 在文档上设置 data-motion,起点是访问者的减弱动效设置;由你的 CSS 和脚本决定要抑制什么。
  • search-picker — 打开搜索框的图标按钮;提交后跳转到搜索页面。它拥有的是一个操作,而不是偏好。
  • link-picker — 一个主页图标,打开由你的应用定义的页面链接菜单(首页、关于我们、联系我们、隐私政策……)。它拥有的是一个操作,而不是偏好。
  • share-picker — 打开原生分享面板或使用方提供的目的地列表,外加复制网址。它拥有的是一个操作,而不是偏好:不应用任何东西,也不保存任何东西。
  • date-time-picker — 一个文本字段加上用于日期、时间或两者的 APG 日期选择对话框。它拥有的是一个表单值,而不是偏好:ISO 字符串可与 <input type="date"> 来回转换。
git clone https://github.com/LilyDesignSystem/lily-design-system-svelte-helpers

Svelte 目录是规范参考;React、Vue、Angular、HTML、Nunjucks、Web Components 和 Blazor 的移植版逐项契约与之一致。参见辅助组件教程。

无障碍

组件以 WCAG 2.2 AAA 为目标。它们遵循这些模式:

  • 用语义化 HTML 元素而不是通用的 <div>。
  • 用 <label for="id"> 把标签与输入关联起来。
  • 用 aria-labelledby / aria-describedby 做相互引用。
  • 用 aria-invalid + aria-errormessage 表示错误状态。
  • 用 role="alert" 和 aria-live 表示动态内容。
  • 用 aria-pressed、aria-expanded、aria-current 表示状态。
  • 为网格使用漫游式 tabindex。

焦点指示器刻意由使用方提供——Lily 从不绘制与你的设计冲突的默认焦点环。示例应用在其所有路由上都保持干净的 axe-core 基线。

国际化

每个标签、占位符、错误消息和按钮文字都是一个属性。没有硬编码的字符串。接入你选择的翻译框架——Paraglide、i18next、vue-i18n、react-intl、.resx 文件,什么都行。

对于日期、数字和货币,组件接受预先格式化的字符串:你用 Intl.DateTimeFormat / Intl.NumberFormat / 你喜欢的库进行格式化,然后传入结果。

locale-picker 辅助组件通过在文档根上设置 lang 和 dir,向你的 i18n 库传达所选的区域设置。

测试

每个框架子项目都使用其惯用技术栈附带自己的测试:

  • HTML:在真实浏览器中运行的 WebDriverIO。
  • Svelte: Vitest + @testing-library/svelte.
  • React: Vitest + @testing-library/react.
  • Vue: Vitest + @testing-library/vue.
  • Angular:Vitest + TestBed(通过 Analog 的 Vite 插件)。
  • Nunjucks:带渲染辅助函数的 Vitest。
  • Blazor: bUnit.

测试只使用 Vitest 的内置匹配器——从不使用 jest-dom 匹配器。这让测试套件保持可移植。示例应用还增加了 Playwright 端到端套件、axe-core 无障碍基线和响应式视口扫描。

AI 代理

本站在根目录发布 llms.txt 和 llms.json——最重要页面的精选地图,供任何遵循 llms.txt 约定的工具使用。

规范单体仓库还提供两个 Claude 技能:lily-design-system-skill,一个通用技能,为使用该系统构建的人涵盖 Lily 的概念、术语和组合模式;以及 lily-design-system-maintainer-skill,一个技术技能,为在其上工作的人涵盖单体仓库所需的文件布局和工具。两者都位于规范单体仓库的根目录。

故障排查

组件能渲染,但看起来没有样式

这是 headless 在按预期工作——组件不附带任何 CSS。要么针对组件的 kebab-case 类编写 CSS(每个目录页面上都有显示),要么链接 45 个现成主题之一。

我的 CSS 似乎没能覆盖主题

应该可以——主题选择器包裹在 :where(...) 中,其优先级为零。如果某条规则仍然输了,请检查你的样式表是否在主题的 <link> 之后加载,以及选择器是否确实匹配组件的类钩子。

pnpm install 因对等依赖或版本错误而失败

使用较新的 pnpm(v10+)和 Node 22+。每个仓库都在 package.json 中固定了其框架版本;如果你的全局工具链较旧,pnpm env use --global lts 是最快的解决办法。

屏幕阅读器为某个控件朗读了错误的名称

检查组件必需的 label 属性——没有可见文字的组件需要它;而使用方提供并通过其余属性传入的 aria-label / aria-labelledby 会刻意优先于内置的连线。每个目录页面都记录了该组件的 ARIA 契约。

theme-picker 辅助组件不切换样式表

确认 themesUrl 指向浏览器可获取的目录(把 themes/ 文件作为静态资源提供),并且你的 themes 属性中的主题标识符与文件名一致。该辅助组件替换的是一个受管理的 <link data-lily-theme-picker> 的 href——在开发者工具中检查它,就能看到被请求的网址。

其他东西坏了

请在相关仓库(github.com/LilyDesignSystem)提交议题并附上最小复现——或查看社区与支持。

参与贡献

Lily 还很年轻,欢迎协作。目前最有用的贡献是:

  • 新组件(尤其是来自成熟设计系统的模式)。
  • 新主题——每个都是一份独立样式表,范围明确的首个拉取请求。
  • 更好的示例样式——展示什么是可能的。
  • 示例应用字符串的翻译。
  • 附带最小复现的缺陷报告。
  • 借助屏幕阅读器和辅助技术进行的无障碍审计。

请在相关仓库(github.com/LilyDesignSystem)提交议题和拉取请求。

社区与支持

  • 问题与缺陷报告 — 请在相关仓库(github.com/LilyDesignSystem)提交议题。
  • 电子邮件 — 维护者会阅读 joel@joelparkerhenderson.com,欢迎协作、指导和反馈。
  • 镜像 — Lily 还会推送到 Codeberg 和 GitLab,这样你可以在自己喜欢的平台上参与。
  • 行为准则 — 项目遵循标准的行为准则;请友善待人,以善意揣度他人。

常见问题

为什么用 headless 而不是自带样式?

预设样式的组件很方便——直到它们和你的品牌不匹配。headless 组件前期多一点工作,但让你完全掌控视觉设计。示例应用和 45 个主题展示了设置样式的方法;你可以直接采用,也可以完全替换。更完整的论述见为什么选择 Lily。

为什么有这么多组件?

Lily 的目标是覆盖大多数应用所需的模式,而不强迫你从零构建——包括国家标识符输入和编辑式滚动叙事这类更深入的场景。目录借鉴了十几个成熟的设计系统,再加上原创工作——参见关于。

我能把 Lily 和 Tailwind 一起用吗?

可以。每个组件都暴露一个 kebab-case 根类,外加使用方提供的 className / class。想怎么在上面叠加 Tailwind 工具类都可以。

我能把 Lily 和 DaisyUI 这类语义化 CSS 框架一起用吗?

可以。根元素上的 kebab-case 类名可作为语义化 CSS 钩子。把 Lily 与语义化框架搭配,你就得到仍然尊重 ARIA 和 i18n 的预设样式组件。

有 npm 包吗?

偏好辅助组件以软件包形式提供,并有 npm/NuGet 发布流水线。headless 组件库的设计目的是被克隆或直接纳入项目——源代码就是交付物,所以你可以阅读、裁剪并完全掌握你所发布的内容。headless 库发布到包注册表仍在路线图上。

为什么是多重许可?

不同的项目有不同的许可需求。BSD 和 MIT 是宽松的,Apache-2.0 带有专利授权,而 GPL 选项支持 copyleft。选择适合你情况的即可。

我该如何报告缺陷或请求新功能?

在相关的 GitHub 仓库提交议题,或发邮件至 joel@joelparkerhenderson.com。