掌握 shadcn/ui:从安装、配置到实战技巧
前言
在现代前端开发中,React 组件库极大地提升了我们的开发效率。然而,传统的组件库如 Material-UI 或 Ant Design,虽然功能强大,但也常常因为过度封装、样式定制困难、打包体积过大等问题而受到诟病。
shadcn/ui 提供了一种全新的思路。它不是一个传统的组件库,而是一组可重用的、无障碍的、样式自由的组件集合。你可以通过命令行工具将这些组件直接引入到你的项目中,它们就成为了你自己的代码,你可以随心所欲地修改和扩展。
本文将带你深入了解 shadcn/ui,从零开始,一步步掌握其安装、配置、使用及高级技巧,帮助你构建出既美观又高效的应用程序。
什么是 shadcn/ui?
在我们开始之前,最重要的一点是:shadcn/ui 不是一个组件库。
它更像是一个“组件代码生成器”。当你需要一个按钮(Button)时,你不是从一个 npm 包中导入 Button 组件,而是运行一个命令,这个命令会将 Button 组件的源代码(一个 React 组件文件)直接复制到你的项目源码目录中。
这种模式带来了几个核心优势:
- 完全所有权:组件代码就在你的项目中,你可以像对待自己写的代码一样,完全控制它的逻辑、样式和行为。
- 易于定制:由于代码是你的,修改样式或功能变得非常直接。你不需要通过复杂的
props或者CSS-in-JS的theme来覆盖默认样式。直接修改组件的className或者 JSX 结构即可。 - 最小打包体积:你的应用最终打包时,只会包含你实际使用的组件代码,不会引入任何额外的、你不需要的库代码。
- 基于 Tailwind CSS:
shadcn/ui的所有组件都使用 Tailwind CSS 进行样式设计,如果你熟悉 Tailwind,那么定制样式会非常得心应手。
一、安装与配置
1. 环境准备
在开始之前,请确保你的开发环境满足以下要求:
- Node.js (v14.0.0 或更高版本)
- 一个基于 React 的项目(推荐使用 Next.js,但 Create React App 或其他框架也可以)
- 项目中已经配置好 Tailwind CSS
如果你的项目还没有配置 Tailwind CSS,请先根据 Tailwind CSS 官方文档 进行安装和配置。
2. 初始化 shadcn/ui
打开你的项目根目录,在终端中运行以下命令:
bash
npx shadcn-ui@latest init
这个命令会引导你完成一系列的配置选项:
-
Would you like to use TypeScript (recommended)? (yes / no)
> 建议选择yes,shadcn/ui对 TypeScript 有着良好的支持。 -
Which style would you like to use? (Default / New York)
> 这是两种预设的视觉风格,Default更加简约,New York则更具现代感。你可以随时在components.json文件中更改。 -
Which color would you like to use as base color? (Slate / Gray / Zinc / Neutral / Stone)
> 选择一个基础色系,它会影响所有组件的默认颜色。 -
Where is your
global.css?
> 指定你的全局 CSS 文件路径,通常是app/globals.css或src/index.css。 -
Would you like to use CSS variables for theming? (yes / no)
> 强烈建议选择yes,这会让你在后续实现主题切换(如深色模式)时变得非常容易。 -
Where is your
tailwind.config.js(ortailwind.config.ts)?
> 指定你的 Tailwind CSS 配置文件路径。 -
Configure import alias for components?
> 配置组件的导入别名,例如~/components,这样你就可以通过@/components/ui/button而不是../../components/ui/button来导入组件。 -
Configure import alias for utils?
> 配置工具函数的导入别名,例如~/lib/utils。 -
Are you using React Server Components? (yes / no)
> 如果你使用 Next.js App Router,请选择yes。
完成这些步骤后,shadcn/ui 会自动完成以下工作:
- 在你的
package.json中添加必要的依赖(如tailwindcss-animate,class-variance-authority,lucide-react等)。 - 更新你的
tailwind.config.js文件,添加shadcn/ui需要的主题和插件配置。 - 创建一个
components.json文件,用于记录你的shadcn/ui配置。 - 创建一个工具函数文件(例如
lib/utils.ts),其中包含一个cn函数,用于合并 Tailwind CSS 类名。
现在,你的项目就已经准备好使用 shadcn/ui 了。
二、添加和使用组件
1. 添加组件
shadcn/ui 的魅力在于按需添加。假设你需要一个按钮和一个卡片。
在终端中运行:
bash
npx shadcn-ui@latest add button card
这个命令执行后,你会发现你的 components 目录下多了两个文件:ui/button.tsx 和 ui/card.tsx。
这就是 shadcn/ui 的核心——组件代码直接进入了你的项目。
2. 使用组件
现在,你可以在你的 React 组件中像使用本地组件一样使用它们:
“`tsx
// app/page.tsx
import { Button } from “@/components/ui/button”;
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from “@/components/ui/card”;
export default function HomePage() {
return (
This is the card content area where you can add forms, text, or any other elements.
);
}
“`
上面的代码创建了一个简单的卡片,其中包含标题、描述、内容以及两个操作按钮。注意 Button 组件有一个 variant 属性,shadcn/ui 的组件通常都提供了类似的高度可定制的 props。
3. 定制组件
shadcn/ui 最强大的地方在于定制。
a. 通过类名定制
假设你想让 “Deploy” 按钮的背景色变为绿色。你不需要复杂的 API,直接在你的代码中添加 Tailwind CSS 类即可:
tsx
<Button className="bg-green-500 hover:bg-green-600">Deploy</Button>
b. 修改组件源代码
如果需要更深度的定制,比如给所有 Button 组件添加一个默认的 icon 位置。你可以直接打开 components/ui/button.tsx 文件进行修改。
原始的 button.tsx 可能看起来像这样:
“`tsx
// components/ui/button.tsx
import * as React from “react”
// … imports
const Button = React.forwardRef
({ className, variant, size, asChild = false, …props }, ref) => {
const Comp = asChild ? Slot : “button”
return (
)
}
)
“`
你可以轻松地修改它,比如添加一个 leftIcon prop:
“`tsx
// components/ui/button.tsx (修改后)
export interface ButtonProps extends React.ButtonHTMLAttributes
asChild?: boolean
leftIcon?: React.ReactNode; // 添加新的 prop
}
const Button = React.forwardRef
({ className, variant, size, asChild = false, leftIcon, children, …props }, ref) => {
const Comp = asChild ? Slot : “button”
return (
{leftIcon && {leftIcon}} {/ 添加 icon 的渲染逻辑 /}
{children}
)
}
)
“`
现在,你项目中的所有 Button 组件都可以接受 leftIcon 这个 prop 了。这就是拥有代码所有权带来的灵活性。
三、高级技巧
1. 主题与深色模式
如果你在初始化时选择了使用 CSS 变量,那么实现深色模式会非常简单。
首先,安装 next-themes:
bash
npm install next-themes
然后,创建一个 ThemeProvider:
“`tsx
// components/theme-provider.tsx
“use client”
import * as React from “react”
import { ThemeProvider as NextThemesProvider } from “next-themes”
import { type ThemeProviderProps } from “next-themes/dist/types”
export function ThemeProvider({ children, …props }: ThemeProviderProps) {
return
}
“`
在你的根布局(app/layout.tsx)中使用它:
“`tsx
// app/layout.tsx
import { ThemeProvider } from “@/components/theme-provider”
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
{children}
)
}
“`
最后,创建一个主题切换按钮:
“`tsx
// components/mode-toggle.tsx
“use client”
import * as React from “react”
import { Moon, Sun } from “lucide-react”
import { useTheme } from “next-themes”
import { Button } from “@/components/ui/button”
export function ModeToggle() {
const { theme, setTheme } = useTheme()
return (
)
}
“`
现在,你就可以在你的应用中自由切换浅色和深色模式了。shadcn/ui 的所有颜色都通过 CSS 变量定义,所以主题切换会无缝生效。
2. 构建复合组件
shadcn/ui 的组件设计哲学鼓励组合。你可以将基础组件组合成更复杂的、符合你业务需求的组件。
例如,你可以创建一个 PageHeader 组件,它由 h1 标签和一个 Button 组成:
“`tsx
// components/page-header.tsx
import { Button, ButtonProps } from “@/components/ui/button”;
interface PageHeaderProps {
title: string;
actionText?: string;
onActionClick?: () => void;
actionButtonProps?: ButtonProps;
}
export function PageHeader({ title, actionText, onActionClick, actionButtonProps }: PageHeaderProps) {
return (
{title}
{actionText && onActionClick && (
)}
);
}
“`
这样,你就在整个应用中有了一个统一的页面头部组件,并且它依然是完全可定制的。
结论
shadcn/ui 为 React 开发带来了新的范式。它通过将组件代码的所有权交还给开发者,解决了传统组件库的许多痛点。它让你在享受高质量、设计精良的组件基础的同时,又不失灵活性和控制力。
选择 shadcn/ui,意味着你选择了一种更现代、更可控、更贴近项目本身的方式来构建你的用户界面。如果你厌倦了与组件库的样式系统作斗争,希望能够更自由地创造,那么 shadcn/ui 绝对值得一试。