shadcn/ui 是 2023 年在 GitHub 上星星数量增长最多的项目,总共获得了 39.5k 的 star,而且在 2023 年 1 月的时候才在 GitHub 发布,接着 2024 年 3 月已经增长到 50K star,这个增长速度非常可怕,究竟它是靠什么让大家都愿意贡献给它一颗 star 呢?
目前一些热门的 UI 库,包括 MUI 、Ant Design 和 Chakra 等等,然后就找到了这个 2023 年最热门的项目。刚开始看 Shadcn UI 组件的样式时并没有觉得令人惊艳,组件也跟其他 UI 库没什么不同,那为什么它会是 2023 年 star 增长数量最多的项目呢?
在这篇文章中会详细介绍 Shadcn UI,并且会整理一些在选择 Shadcn UI 大家会遇到的问题,提供给大家做技术选型的参考。
shadcn ui 简介
首先明确:Shadcn UI 不是 组件库
Shadcn UI 与常见的 MUI、Ant Design 和 Chakra 等等的组件库不一样,它并不是一个组件库,那它是什么呢?
实际上它是汇集了各种组件的一个项目,你可以选择需要的组件,然后复制粘贴到你的项目中。而且它没有 npm 包,这意味着你不会在 package.json 中看到 Shadcn UI。 看到它的使用方式,你可能会疑惑,这个和其他的组件库没有什么不同啊?
Shadcn UI 的底层是 Radix UI
Radix UI 是一个 headless 组件库,这表示它的组件没有任何的样式,它提供了可以定制化样式的方式,让我们自定义组件的样式。
此外,Radix UI 的所有组件都符合 WAI-ARIA 的要求,如果你需要建立具有可访问性的项目,Radix UI 无疑是一个好的选择。 另外一点,是 Radix UI 的所有组件都可以单独下载,你不用在一开始就安装整包的组件库,而是安装需要的组件到你的项目中即可:
bash
npm install @radix-ui/react-dialog
npm install @radix-ui/react-dropdown-menu
npm install @radix-ui/react-tooltip
如果你不需要 Shadcn UI 提供的样式,也可以自己使用 Radix UI 封装成所需的组件库。
Shadcn UI 使用 Tailwind CSS 封装 Radix UI
Tailwind CSS 无疑是近年来大家最常听到实现了原子化 CSS 的 CSS 框架,而 Shadcn UI 则是用了 Tailwind CSS 封装了 Radix UI 的组件,你从 Shadcn UI 上复制的组件都有 Tailwind CSS 的踪迹。
除了 Tailwind CSS 之外,另一个值得一提的是 class-variance-authority(cva)这个库,这个库也会在 Shadcn UI 中经常看到,它让组件有了 variant 的功能。
使用 Shadcn CLI 下载组件到你的项目
Shadcn UI 的主要功能就是让你复制组件的源代码,它提供了 CLI 跟手动复制两种方式,使用 CLI 便可以很快速地将组件新增到你的项目中:
sql
npx shadcn-ui@latest add button
技术选型的问题
问题1:将 Shadcn UI 的组件源码下载下来,那不得需要自己维护吗?
在看到这个项目的时候,很多人都会有这个问题,如果遇到 bug 的时候怎么办?这的问题不太准确,有两点是大家需要思考的。
首先,不论是 Shadcn UI、MUI 或 Ant Design,只要修改了其组件的样式都需要我们自己维护,所以维护这个问题是必然的,除非你不需要定制样式。
其二,Shadcn UI 的底层是 Radix UI,组件的功能是实现在 Radix 上面,跟 Shadcn UI 没有关系,所以当发生了 bug 或是需要新功能时,则是要去看 Radix UI 是否有更新,而不是 Shadcn UI。
所以这个问题的答案是"对的,你要自己维护,但是只需要维护样式的部分"。
问题2:Shadcn UI 的项目 issue 很多怎么办?
Shadcn 作者在加入 Vercel 之后更新频率变低了,所以 issue 现在蛮多的,而且更新速度并不一定会如大家预期。
但如上个问题所述,Shadcn UI 里面只有样式,组件的功能是 Radix UI 提供的,所以当发生问题时要看的是 Radix UI 的状况,而并非 Shadcn UI。除非你需要的是 Shadcn UI 的 issue 提到的某个新的功能或是样式,但届时也许也是用复制粘贴的方式去更新 codebase 中的组件。
什么时候不要使用 Shadcn UI?
我想这个是大家都想问的一个问题,可以快速总结为几点:
- 你不想要自己维护所有的样式:
因为 Radix UI 的组件都没有样式,这意味着所有的组件样式都得自己建构跟维护,这是个双刃剑,你拥有组件样式完整的控制权,但就得花费更多心力去维护。如果你依赖了 Ant Design,而按钮只改了 border-radius,其他样式则是由 Antd 提供,不用花费很多心力去维护样式,只需要担心升级的时候会不会跑版,或是圣诞节会不会突然跑出圣诞彩蛋。
- Radix UI 无法满足你的需求:
Radix UI 毕竟还是比较小众的组件库,其星星数只有 3.4K 而已,比起 Shadcn UI 少了 10 几倍,如果遇到 bug 或是需要新功能时,能得到的社区资源相当有限
- 不想自己维护组件的文档:
如果在会持续迭代的项目中使用 Shadcn UI 还有一个明显的缺点是"文档必须随着组件持续更新",当我们使用较完整的组件库像是 Ant Design、MUI 等等,其组件的用法更新时会有官方负责维护文档,但我们使用 Shadcn UI 代表着多了一个可能会需要持续更新组件的成本。
Shadcn UI 跟 Ant Design 该怎么选
Ant Design 的优点:
- 涵盖了非常广泛的使用者行为
- form 系统很完善
- 提供的组件非常多样化
- 阿里旗下的套件,对于维护性毋庸置疑
Ant Design 的缺点:
- 前几年发生了圣诞彩蛋事件 🥚
- 功能多所以相对来说体积较大
- 大版本经常会有 breaking change
- 表格等部分组件性能不太好
Shadcn UI 的优点:
- theme 的系统很完善,而且简单
- 拥有高度定制化的弹性,因为你拥有了源代码
- 较为轻量,你不用把所有的套件都安装到你的项目下
- 符合 A11y 的规范
Shadcn UI 的缺点:
- 未来的更新可能会比较辛苦一点,因为你拥有了所有的源代码,更新组件的同时可能需要同时维护文档
- 组件较为简单,通常都需要自己再定制组件
- 对于 table 等等有大量数据渲染的组件较弱
- 对于复杂的表单,form的功能较弱
可以简单总结为,如果 Radix 提供的组件功能可以符合需求,Shadcn UI 也能符合你的需求,不需要安装较重的 Ant Design。但是相对起来 Shadcn UI 需要维护的成本有可能会高一些,因为你需要维护所有的样式及文档。
简单的应用或是不会需要持续迭代的项目也许 Shadcn UI 满足你的需求,而且使用上也很简单;而 Ant Design 的功能很完善,对于如果是需要大型 form 或是 table 的应用,还有许多额外的功能,在复杂的应用中选择 Ant Design 是个不错的选择。
其他在使用 Shadcn UI 遇到的问题
1.form 组件的结构有点怪
这是 Shadcn UI 提供的 form 代码片段,可以看到 form 使用了2次,为什么不是一个 form 呢?
javascript
export function ProfileForm() {
// ...
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="username"
render={({ field }) => (
<FormItem>
<FormLabel>Username</FormLabel>
<FormControl>
<Input placeholder="shadcn" {...field} />
</FormControl>
<FormDescription>
This is your public display name.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</Form>
)
}
Shadcn UI 的 Form 封装并非基于 Radix UI 的 form,而是采用了 react-hook-form 进行封装。这可能会在名称上给人造成一定的混淆。
2. 在 Shadcn UI 中,DatePicker 并非由 Radix UI 提供
因为Radix UI 并没有 DatePicker组件,所以使用了 React DayPicker 组件。然而,该组件功能相对较少,不具备选择月份或年份的功能。
在 ReactDayPicker 的官方 GitHub 中,MonthPicker 功能已超出其范畴,若有此需求,可能需要自行制作。其想法较为简单,通过年份导航,"面板"将显示月份。另外,React DayPicker 依赖的是 date-fns,如果想要使用 dayjs,则需要考虑其他套件。
Shadcn Vue
社区针对 Vue(3) ,也退出了对于的 vue 版本的 Shadcn,目前在 vite 下也能很好的使用。
Unocss
如果你想使用 Unocss 代替 Tailwindcss,借助 unocss-preset-shadcn插件,也能很好的使用。
uno.config.ts:
css
import { presetShadcn } from 'unocss-preset-shadcn'
export default defineConfig({
presets: [
presetShadcn({
color: 'neutral',
radius: 0.5
}),
]
)}
components.json:
bash
{
"$schema": "https://shadcn-vue.com/schema.json",
"style": "default",
"typescript": true,
"tsConfigPath": ".nuxt/tsconfig.json",
"tailwind": {
"config": "tailwind.config.js",
"css": "assets/styles/index.css",
"baseColor": "neutral",
"cssVariables": true
},
"framework": "vite",
"aliases": {
"components": "~/components",
"utils": "~/lib/utils",
"ui": "~/components/ui"
}
}
你也可以在 nuxt 中使用,更多内容请查看:https://nuxt.com/modules/shadcn
总结
看完这篇文章你应该可以了解 Shadcn UI 的有哪些特性,我们知道 Shadcn UI 跟许多的 UI 库不一样,它是通过源码的方式来使用,未来要修改样式都是由你自己决定,也这意味着你需要花更多精力去维护。
我们也知道了一些常见在技术选型中的问题,说到底 Shadcn UI 是 headless UI + Tailwind 的组合,在市面上还是有许多headless UI 的选择的,如果你要打造自己的组件库,可以选择一套 headless UI 并且自己定制化。