shadcn/ui
是一个由社区维护的现代 UI 组件库模板集合,专为 React + Tailwind CSS 生态设计,主打:
特性 | 说明 |
---|---|
✨ 美观现代 | 默认采用干净、优雅的设计(类似 Vercel / Linear) |
Tailwind 驱动 | 100% Tailwind CSS 控制样式,自由修改 |
⚛️ Radix UI 底层 | 提供无障碍可访问性支持(A11y) |
可组合 | 所有组件是“导入代码”的方式,无 run-time 限制 |
可维护性强 | 你拥有组件代码本体(不再受限组件黑箱) |
分类 | 组件 |
---|---|
表单 | Input , Textarea , Select , Switch , Checkbox , Form |
弹窗 | Dialog , Popover , Tooltip , AlertDialog , Sheet |
导航 | Tabs , Accordion , DropdownMenu , NavigationMenu |
其他 | Toast , Badge , Card , Avatar , Skeleton , Progress |
支持 Vite、Next.js、Remix 等现代 React 框架。
npx shadcn-ui@latest init
你会被提示:
components/ui
)Button
, Dialog
)npx shadcn-ui@latest add button
生成的文件:
components/ui/button.tsx
你可以自由修改样式类或行为。
特性 | shadcn/ui | MUI | Ant Design | Chakra UI |
---|---|---|---|---|
样式控制 | ✅ 完全控制 | ❌ 封闭 | ❌ 封闭 | ⚠️ 类似 |
设计系统 | ⚠️ 提供默认样式 | ✅ 有 | ✅ 有 | ✅ 有 |
SSR 支持 | ✅ 优秀 | ⚠️ 需调整 | ⚠️ 有限 | ⚠️ 有限 |
适合 Tailwind | ✅ 最佳搭配 | ❌ 不兼容 | ❌ 不兼容 | ❌ 有冲突 |
适合你吗? | 条件 |
---|---|
✅ 喜欢 Tailwind | 强烈推荐 |
✅ 需要 SSR / RSC 兼容 | 推荐 |
✅ 想要样式可控且干净 UI | 推荐 |
❌ 想要“开箱即用 + Theme切换 + 组件黑盒” | 不太适合 |
下面是一个基于 shadcn/ui
、React
和 Tailwind CSS
封装的 AI 聊天界面模板,具备如下特性:
shadcn/ui
组件:Input
, Button
, Card
, ScrollArea
, Skeleton
npx shadcn-ui@latest init
npx shadcn-ui@latest add button input card scroll-area
ChatPage.tsx
import { useState, useRef, useEffect } from "react"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
import { ScrollArea } from "@/components/ui/scroll-area"
import { Card, CardContent } from "@/components/ui/card"
interface Message {
role: "user" | "assistant"
content: string
}
export default function ChatPage() {
const [messages, setMessages] = useState<Message[]>([])
const [input, setInput] = useState("")
const scrollRef = useRef<HTMLDivElement>(null)
const handleSend = async () => {
if (!input.trim()) return
const userMsg: Message = { role: "user", content: input }
setMessages((prev) => [...prev, userMsg])
setInput("")
// 模拟 AI 回复
setTimeout(() => {
const aiMsg: Message = {
role: "assistant",
content: `你说的是:“${userMsg.content}”`
}
setMessages((prev) => [...prev, aiMsg])
}, 1000)
}
useEffect(() => {
scrollRef.current?.scrollIntoView({ behavior: "smooth" })
}, [messages])
return (
<div className="flex flex-col h-screen p-4 max-w-2xl mx-auto">
<h2 className="text-2xl font-bold mb-4">AI Chat Assistant</h2>
<ScrollArea className="flex-1 border rounded-lg p-4 space-y-2 bg-muted">
{messages.map((msg, index) => (
<Card key={index} className={msg.role === "user" ? "ml-auto bg-white" : "mr-auto bg-gray-100"}>
<CardContent className="p-3 text-sm whitespace-pre-wrap">
<strong>{msg.role === "user" ? "You" : "AI"}:</strong> {msg.content}
</CardContent>
</Card>
))}
<div ref={scrollRef} />
</ScrollArea>
<div className="mt-4 flex gap-2">
<Input
placeholder="Ask something..."
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === "Enter" && handleSend()}
/>
<Button onClick={handleSend}>Send</Button>
</div>
</div>
)
}
body {
@apply bg-background text-foreground;
}
功能 | shadcn 组件建议 |
---|---|
Markdown 渲染 | react-markdown 自定义卡片内容 |
Skeleton 骨架 | Skeleton 组件用于 AI 回复加载中 |
多轮对话滚动 | ScrollArea + useRef 自动滚动到底部 |
AI 流式回复 | 用 useEffect 模拟逐字加载即可 |