Card
Card 从 HeroUI v2 到 v3 的迁移指南。
完整的 API 参考、样式指南与高级示例请参阅 v3 Card 文档。本指南只关注从 HeroUI v2 的迁移。
结构变化
在 v2 中,Card 使用独立导出的子组件:CardHeader、CardBody、CardFooter。
import { Card, CardHeader, CardBody, CardFooter } from "@heroui/react";
export default function App() {
return (
<Card>
<CardHeader>Header</CardHeader>
<CardBody>Body</CardBody>
<CardFooter>Footer</CardFooter>
</Card>
);
}在 v3 中,Card 使用复合组件模式,子部件以 Card.* 形式显式组合:
import { Card } from "@heroui/react";
export default function App() {
return (
<Card>
<Card.Header>
<Card.Title>Title</Card.Title>
<Card.Description>Description</Card.Description>
</Card.Header>
<Card.Content>Body content</Card.Content>
<Card.Footer>Footer</Card.Footer>
</Card>
);
}关键变化
1. 组件结构
v2: 独立组件:CardHeader、CardBody、CardFooter
v3: 复合组件:Card.Header、Card.Title、Card.Description、Card.Content、Card.Footer
2. 组件命名变化
| v2 组件 | v3 组件 | 说明 |
|---|---|---|
CardHeader | Card.Header | 功能等价 |
CardBody | Card.Content | 已重命名 |
CardFooter | Card.Footer | 功能等价 |
| — | Card.Title | 新增:用于标题区标题 |
| — | Card.Description | 新增:用于标题区描述 |
3. Prop 变更
| v2 prop | v3 位置 | 说明 |
|---|---|---|
shadow | — | 已移除(例如使用 Tailwind shadow-sm、shadow-md) |
radius | — | 已移除(例如使用 Tailwind rounded-lg) |
fullWidth | — | 已移除(例如使用 Tailwind w-full) |
isHoverable | — | 已移除(请使用 Tailwind 的 hover class) |
isPressable | — | 请在 Card 内使用 button 或 a 包裹可点击区域 |
isBlurred、isFooterBlurred | — | 已移除(例如使用 Tailwind backdrop-blur-*) |
isDisabled | — | 已移除(请使用条件渲染处理) |
disableAnimation、disableRipple | — | 已移除 |
allowTextSelectionOnPress | — | 已移除(不再适用) |
classNames | — | 在各子部件上使用 className |
4. 变体
v2: 无 variant prop(主要通过 shadow / radius 控制观感)
v3: 提供 variant prop:transparent、default、secondary、tertiary
迁移示例
Card 结构
{/* Basic structure */}
<Card>
<CardHeader>Header</CardHeader>
<CardBody>Body content</CardBody>
<CardFooter>Footer</CardFooter>
</Card>
{/* With title and description */}
<Card>
<CardHeader className="pb-0 pt-2 px-4 flex-col items-start">
<p className="text-tiny uppercase font-bold">Daily Mix</p>
<small className="text-default-500">12 Tracks</small>
<h4 className="font-bold text-large">Frontend Radio</h4>
</CardHeader>
<CardBody>Content</CardBody>
</Card>{/* 基础结构 */}
<Card>
<Card.Header>
<Card.Title>Header</Card.Title>
</Card.Header>
<Card.Content>Body content</Card.Content>
<Card.Footer>Footer</Card.Footer>
</Card>
{/* 标题 + 描述 */}
<Card>
<Card.Header>
<Card.Title>Frontend Radio</Card.Title>
<Card.Description>Daily Mix • 12 Tracks</Card.Description>
</Card.Header>
<Card.Content>Content</Card.Content>
</Card>可点击的 Card
<Card
isPressable
shadow="sm"
onPress={() => console.log("pressed")}
>
<CardBody>Clickable card</CardBody>
</Card><Card className="shadow-sm">
<button
type="button"
className="w-full cursor-pointer text-left"
onClick={() => console.log("pressed")}
>
<Card.Content>Clickable card</Card.Content>
</button>
</Card>带图片的 Card
<Card className="py-4">
<CardHeader className="pb-0 pt-2 px-4 flex-col items-start">
<h4 className="font-bold text-large">Frontend Radio</h4>
</CardHeader>
<CardBody className="overflow-visible py-2">
<Image
alt="Card background"
className="object-cover rounded-xl"
src="https://example.com/image.jpg"
width={270}
/>
</CardBody>
</Card><Card className="py-4">
<Card.Header>
<Card.Title>Frontend Radio</Card.Title>
</Card.Header>
<Card.Content className="overflow-visible py-2">
<img
alt="Card background"
className="object-cover rounded-xl w-full"
src="https://example.com/image.jpg"
/>
</Card.Content>
</Card>页脚背景模糊(Blurred Footer)
import { Card, CardFooter, Image, Button } from "@heroui/react";
<Card isFooterBlurred className="border-none" radius="lg">
<Image
alt="Woman listing to music"
className="object-cover"
height={200}
src="https://example.com/image.jpg"
width={200}
/>
<CardFooter className="justify-between before:bg-white/10 border-white/20 border-1 overflow-hidden py-1 absolute before:rounded-xl rounded-large bottom-1 w-[calc(100%_-_8px)] shadow-small ml-1 z-10">
<p className="text-tiny text-white/80">Available soon.</p>
<Button className="text-tiny text-white bg-black/20" size="sm">
Notify me
</Button>
</CardFooter>
</Card>import { Card, Button } from "@heroui/react";
<Card className="border-none rounded-lg relative overflow-hidden">
<img
alt="Woman listing to music"
className="object-cover w-full h-[200px]"
src="https://example.com/image.jpg"
/>
<Card.Footer className="justify-between backdrop-blur-md bg-white/10 border-white/20 border overflow-hidden py-1 absolute rounded-lg bottom-1 w-[calc(100%_-_8px)] shadow-sm ml-1 z-10">
<p className="text-tiny text-white/80">Available soon.</p>
<Button className="text-tiny text-white bg-black/20" size="sm">
Notify me
</Button>
</Card.Footer>
</Card>Card 变体
{/* v2 doesn't have variants, uses shadow/radius */}
<Card shadow="md" radius="lg">
<CardBody>Content</CardBody>
</Card><Card variant="default">
<Card.Content>Content</Card.Content>
</Card>
<Card variant="secondary">
<Card.Content>Content</Card.Content>
</Card>样式变化
v2:classNames prop
<Card
classNames={{
base: "custom-base",
header: "custom-header",
body: "custom-body",
footer: "custom-footer"
}}
/>v3:直接使用 className prop
<Card className="custom-base">
<Card.Header className="custom-header">
<Card.Title>Title</Card.Title>
</Card.Header>
<Card.Content className="custom-body">
Content
</Card.Content>
<Card.Footer className="custom-footer">
Footer
</Card.Footer>
</Card>组件组成
v3 的 Card 结构如下:
Card (Root)
├── Card.Header (optional)
│ ├── Card.Title (optional)
│ └── Card.Description (optional)
├── Card.Content (optional)
└── Card.Footer (optional)总结
- 组件结构:请使用复合组件,而不是 v2 的独立导出子组件。
CardBody→Card.Content:组件已重命名。- 新增子组件:
Card.Title与Card.Description,用于结构化标题区。 - 大量样式 prop 已移除:请改用 Tailwind CSS class。
- 可点击 Card:不要用
isPressable,改为在 Card 内使用button或链接。 - 模糊效果:请使用 Tailwind
backdrop-blur-*class,而不是相关 prop。 - 变体:新增用于表达语义层级 / 视觉强调度的变体体系。
classNames已移除:在各子部件上使用classNameprop。