Card
Migration guide for Card from HeroUI v2 to v3
Refer to the v3 Card documentation for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.
Structure Changes
In v2, Card used separate components: CardHeader, CardBody, and 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>
);
}In v3, Card uses a compound component pattern with explicit subcomponents:
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>
);
}Key Changes
1. Component Structure
v2: Separate components: CardHeader, CardBody, CardFooter
v3: Compound components: Card.Header, Card.Title, Card.Description, Card.Content, Card.Footer
2. Component Name Changes
| v2 Component | v3 Component | Notes |
|---|---|---|
CardHeader | Card.Header | Same functionality |
CardBody | Card.Content | Renamed |
CardFooter | Card.Footer | Same functionality |
| - | Card.Title | New subcomponent for header titles |
| - | Card.Description | New subcomponent for header descriptions |
3. Prop Changes
| v2 Prop | v3 Location | Notes |
|---|---|---|
shadow | - | Removed (use Tailwind e.g. shadow-sm, shadow-md) |
radius | - | Removed (use Tailwind e.g. rounded-lg) |
fullWidth | - | Removed (use Tailwind w-full) |
isHoverable | - | Removed (use Tailwind hover classes) |
isPressable | - | Use button or link wrapper inside Card |
isBlurred, isFooterBlurred | - | Removed (use Tailwind backdrop-blur-*) |
isDisabled | - | Removed (handle with conditional rendering) |
disableAnimation, disableRipple | - | Removed |
allowTextSelectionOnPress | - | Removed (not applicable) |
classNames | - | Use className on parts |
4. Variants
v2: No variant prop (used shadow/radius for styling)
v3: Has variant prop: transparent, default, secondary, tertiary
Migration Examples
Card Structure
{/* 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>{/* Basic structure */}
<Card>
<Card.Header>
<Card.Title>Header</Card.Title>
</Card.Header>
<Card.Content>Body content</Card.Content>
<Card.Footer>Footer</Card.Footer>
</Card>
{/* With title and description */}
<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>Pressable 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 with Image
<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 Card
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 Variants
{/* 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>Styling Changes
v2: classNames Prop
<Card
classNames={{
base: "custom-base",
header: "custom-header",
body: "custom-body",
footer: "custom-footer"
}}
/>v3: Direct className Props
<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>Component Anatomy
The v3 Card follows this structure:
Card (Root)
├── Card.Header (optional)
│ ├── Card.Title (optional)
│ └── Card.Description (optional)
├── Card.Content (optional)
└── Card.Footer (optional)Summary
- Component Structure: Must use compound components instead of separate components
- CardBody → Card.Content: Component renamed
- New Subcomponents:
Card.TitleandCard.Descriptionfor structured headers - Props Removed: Many styling props removed; use Tailwind CSS classes
- Pressable Cards: Use a button or link inside Card instead of
isPressable - Blur Effects: Use Tailwind
backdrop-blur-*classes instead of props - Variants: New variant system for semantic prominence levels
- ClassNames Removed: Use
classNameprops on individual components