shadcn-svelte 是做什么的?
一个用于 Svelte 构建 UI、组件和设计系统的框架。组件通过 CLI 作为源代码添加到用户项目中。
重要提示: 使用项目的包管理器运行所有 CLI 命令:
npx shadcn-svelte@latest、pnpm dlx shadcn-svelte@latest或bunx --bun shadcn-svelte@latest。以下示例使用npx shadcn-svelte@latest,但请根据项目替换为正确的运行器。
当前项目上下文
读取项目根目录下的 components.json,当需要实时文件布局时,列出 aliases.ui 路径指定的目录(解析规则与 CLI 相同)。
导入(Svelte)
每个组件都位于自己的文件夹中,并有一个 index.ts 桶文件。请参考安装文档:
- 多部分组件(dialog、select、card、field、tabs 等):
import * as Dialog from "$lib/components/ui/dialog",然后使用Dialog.Content、Dialog.Title、Card.Root、Card.Header等——根据桶文件导出的内容(短名称和/或Root as …别名)。 - 单组件桶文件(文件夹中只有一个有意义的组件):使用命名导入——
import { Button } from "$lib/components/ui/button"和<Button>,而不是import * as Button+Button.Root。{ Input }、{ Badge }、{ Spinner }、{ Checkbox }、{ Separator }、{ Skeleton }等也是如此。
import * as Dialog from "$lib/components/ui/dialog";
import { Button } from "$lib/components/ui/button";
import { Separator } from "$lib/components/ui/separator";
使用 components.json 中的实际别名(通常是 $lib/components/ui/...),而不是硬编码路径。
原则
- 优先使用现有组件。 运行
npx shadcn-svelte@latest add(不带参数)浏览可用组件,或在编写自定义 UI 之前查看组件页面。 - 组合,而不是重新发明。 设置页面 = Tabs + Card + 表单控件。仪表盘 = Sidebar + Card + Chart + Table。
- 优先使用内置变体,而不是自定义样式。 使用
variant="outline"、size="sm"等。 - 使用语义化颜色。 使用
bg-primary、text-muted-foreground——永远不要使用像bg-blue-500这样的原始值。
关键规则
这些规则始终强制执行。每条规则链接到一个包含错误/正确代码对的文件。
样式与 Tailwind → styling.md
class仅用于布局,不用于样式。 永远不要覆盖组件的颜色或排版。- 不要使用
space-x-*或space-y-*。 使用flex配合gap-*。对于垂直堆叠,使用flex flex-col gap-*。 - 当宽度和高度相等时,使用
size-*。 使用size-10而不是w-10 h-10。 - 使用
truncate简写。 而不是overflow-hidden text-ellipsis whitespace-nowrap。 - 不要手动使用
dark:颜色覆盖。 使用语义化 token(bg-background、text-muted-foreground)。 - 使用
cn()处理条件类。 不要编写手动的模板字面量三元表达式。 - 不要在覆盖层组件上手动设置
z-index。 Dialog、Sheet、Popover 等组件自己处理堆叠。
表单与输入 → forms.md
- 表单使用
Field.FieldGroup+Field.Field。 永远不要使用原始的div配合space-y-*或grid gap-*进行表单布局。 InputGroup使用InputGroup.Input/InputGroup.Textarea。 不要在InputGroup.Root内部使用原始的Input/Textarea。- 输入框内的按钮使用
InputGroup.Root+InputGroup.Addon。 - 选项集(2-7 个选项)使用
ToggleGroup。 不要使用Button循环并手动管理激活状态。 Field.FieldSet+Field.FieldLegend用于分组相关的复选框/单选按钮。 不要使用带有标题的div。- 字段验证使用
data-invalid+aria-invalid。 在Field上使用data-invalid,在控件上使用aria-invalid。对于禁用状态:在Field上使用data-disabled,在控件上使用disabled。
组件结构 → composition.md
- 项目始终放在它们的分组内。
Select.Item→Select.Group。DropdownMenu.Item→DropdownMenu.Group。Command.Item→Command.Group。 - 自定义触发器。 将控件包裹在
Dialog.Trigger/AlertDialog.Trigger中,或者使用根元素上的bind:open控制打开状态——参见组件文档。 - Dialog、Sheet 和 Drawer 始终需要 Title。
Dialog.Title、Sheet.Title、Drawer.Title对于无障碍性是必需的。如果视觉上隐藏,使用class="sr-only"。 - 使用完整的 Card 组合。
Card.Header/Card.Title/Card.Description/Card.Content/Card.Footer。不要把所有内容都放在Card.Content中。 - Button 没有
isPending/isLoading。 在Button内部组合使用Spinner+disabled;在Spinner上使用data-icon="inline-start"/inline-end以确保正确的间距(import { Button },import { Spinner })。 Tabs.Trigger必须位于Tabs.List内部。 永远不要在Tabs中直接渲染触发器。Avatar始终需要Avatar.Fallback。 用于图片加载失败的情况。
使用组件,而不是自定义标记 → composition.md
- 在编写自定义标记之前,优先使用现有组件。 检查组件是否存在,然后再编写样式的
div。 - 提示使用
Alert。 不要构建自定义样式的 div。 - 空状态使用
Empty。 不要构建自定义的空状态标记。 - Toast 使用
svelte-sonner。 使用来自svelte-sonner的toast()和 UI 文件夹中的 Sonner 组件。 - 使用
Separator而不是<hr>或仅使用边框类的div。 - 使用
Skeleton作为加载占位符。不要使用自定义的animate-pulsediv。 - 使用
Badge而不是自定义样式的 span。
图标 → icons.md
<Button>中的图标使用data-icon。 在图标上使用data-icon="inline-start"或data-icon="inline-end"。- 组件内部的图标不要添加尺寸类。 组件通过 CSS 处理图标尺寸。不要使用
size-4或w-4 h-4。 - 将图标作为组件传递。 从配置的
iconLibrary导入(例如@lucide/svelte),而不是使用字符串键。
CLI
- 预设——从 shadcn-svelte.com 上的设计系统构建器复制编码后的字符串,并将其传递给
npx shadcn-svelte@latest init --preset <code>。
关键模式
这些是最常见的、区分正确 shadcn-svelte 代码的模式。对于边界情况,请参见上面链接的规则文件。
<script lang="ts">
import * as Field from "$lib/components/ui/field";
import { Input } from "$lib/components/ui/input";
import { Button } from "$lib/components/ui/button";
import SearchIcon from "@lucide/svelte/icons/search";
import { Badge } from "$lib/components/ui/badge";
import * as Avatar from "$lib/components/ui/avatar";
</script>
<!-- 表单布局:Field.FieldGroup + Field.Field,而不是 div + Label。 -->
<Field.FieldGroup>
<Field.Field>
<Field.FieldLabel for="email">电子邮件</Field.FieldLabel>
<Input id="email" />
</Field.Field>
</Field.FieldGroup>
<!-- 验证:在 Field 上使用 data-invalid,在控件上使用 aria-invalid。 -->
<Field.Field data-invalid>
<Field.FieldLabel for="email">电子邮件</Field.FieldLabel>
<Input id="email" aria-invalid />
<Field.FieldDescription>无效的电子邮件。</Field.FieldDescription>
</Field.Field>
<!-- 按钮中的图标:使用 data-icon,不加尺寸类。 -->
<Button>
<SearchIcon data-icon="inline-start" />
搜索
</Button>
<!-- 间距:使用 gap-*,而不是 space-y-*。 -->
<div class="flex flex-col gap-4"></div>
<!-- 等宽高:使用 size-*,而不是 w-* h-*。 -->
<Avatar.Root class="size-10">
<Avatar.Image src="/u.png" alt="用户" />
<Avatar.Fallback>U</Avatar.Fallback>
</Avatar.Root>
<!-- 状态颜色:使用 Badge 变体或语义化 token,而不是原始颜色。 -->
<Badge variant="secondary">+20.1%</Badge>
组件选择
| 需求 | 使用 |
|---|---|
| 按钮/操作 | Button,配合适当的变体(`import { Button }) |
| 表单输入 | Input、Select、Combobox、Switch、Checkbox、RadioGroup、Textarea、InputOTP、Slider |
| 在 2–5 个选项间切换 | ToggleGroup.Root + ToggleGroup.Item |
| 数据显示 | Table、Card、Badge、Avatar |
| 导航 | Sidebar、NavigationMenu、Breadcrumb、Tabs、Pagination |
| 覆盖层 | Dialog(模态框)、Sheet(侧面板)、Drawer(底部面板)、AlertDialog(确认框) |
| 反馈 | svelte-sonner(toast)、Alert、Progress、Skeleton、Spinner |
| 命令面板 | Dialog 内部的 Command |
| 图表 | Chart(LayerChart) |
| 布局 | Card、Separator、Resizable、ScrollArea、Accordion、Collapsible |
| 空状态 | Empty |
| 菜单 | DropdownMenu、ContextMenu、Menubar |
| 提示/信息 | Tooltip、HoverCard、Popover |
关键字段
使用 components.json 和文件系统——而不是单独的 info 命令:
aliases→ 使用配置中的实际别名前缀(例如$lib/),永远不要为不相关的项目硬编码。tailwind.css→ 存放主题变量的全局 CSS 文件。编辑此文件以调整主题;除非用户已使用,否则不要添加第二个全局文件。style→ 视觉处理方式(例如nova、vega等)和注册表样式路径。iconLibrary→ 决定图标包(@lucide/svelte、@tabler/icons-svelte等)。永远不要假定为@lucide/svelte。registry→ CLI 获取组件的地方;默认官方注册表位于shadcn-svelte.com。resolvedPaths(概念性)→ CLI 将aliases解析为绝对路径;列出磁盘上的aliases.ui以查看已安装的组件。
有关命令和标志,请参见 cli.md。
组件文档、示例和用法
打开 https://shadcn-svelte.com/docs/components/<name>.md 获取文档和示例。在创建、修复、调试或使用组件时,请先阅读官方页面,以确保遵循文档化的 API。
工作流程
- 获取项目上下文——读取
components.json,并在需要时列出 UI 组件目录。 - 首先检查已安装的组件——在运行
add之前,列出已解析的ui路径下的文件。不要导入尚未添加的组件,也不要重新添加已存在的组件(除非是为了更新)。 - 发现组件——
npx shadcn-svelte@latest add不带参数(交互式列表),或访问文档网站。 - 安装或更新——
npx shadcn-svelte@latest add <name>或注册表 URL。要从注册表刷新现有文件,请使用npx shadcn-svelte@latest update(参见 cli.md)。 - 修复第三方/URL 添加项中的导入——从自定义注册表 URL 添加后,检查是否包含与项目
aliases不匹配的硬编码路径。重写导入以使用components.json中的项目ui/lib别名。 - 审查添加的组件——添加后,读取添加的文件并验证组合(分组、标题、验证属性)。将图标导入与
iconLibrary对齐。 - 远程注册表项——通过 URL 添加是显式操作;如果用户想要来自未知来源的组件,请在运行
add之前确认注册表 URL 或项目。
基于 DESIGN.md 的设计系统
当用户要求从 DESIGN.md(或品牌规范)创建设计系统时,无论是否带有预设,请完整遵循 design-system.md:
- 对于新应用,使用
npx sv create <app>搭建 SvelteKit(或根据要求使用 Svelte + Vite),然后使用npx shadcn-svelte@latest init --preset <code>初始化。如果没有代码,选择符合 DESIGN.md 的样式并传递其名称,例如init --preset luma;React 预设代码和搭建标志不适用。在现有应用中,保留本地的自定义设置。 - 在新应用中,使用
add --all --yes安装每个组件;在现有应用中,仅添加缺少的组件。 - 在编辑之前,阅读 DESIGN.md 的前置元数据、注意事项和已知差距。
- 将其 token 映射到
components.json的tailwind.css中的变量。固定半径、阴影、字体和type-*工具类。 - 重新设置已安装的
tailwind-variants变体和相关的样式 CSS。一起更改控件高度。 - 按照 design-system-page.md 构建页面:对比度检查的颜色角色、类型样本、固定的状态矩阵、边界情况、注意事项对照对、配方。使用
scripts/showcase-coverage.mjs检查导入,然后验证每个组件的渲染。 - 在浏览器中验证:
svelte-check、生产构建包括 SSR、无控制台错误、页面在顶部加载、无水平溢出、暗色模式正常。
更新组件
使用 update 命令从注册表拉取项目中已有组件的最新版本。update 后使用 git diff 查看更改。
- 提交或暂存本地工作。
- 运行
npx shadcn-svelte@latest update [component]或--all。 - 如果自定义了文件,则解决合并冲突。
- 永远不要在没有用户明确批准的情况下在
add上使用--overwrite,以免破坏有意的编辑。
快速参考
# 在项目中初始化 shadcn-svelte
……
[已截断以进行翻译]