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.
Overview
The Card component in HeroUI v3 has been redesigned with a compound component pattern, requiring explicit structure with Card.Header, Card.Title, Card.Description, Card.Content, and Card.Footer components.
Structure Changes
v2: Separate Components
In v2, Card used separate components: CardHeader, CardBody, and CardFooter:
import { Card, CardHeader, CardBody, CardFooter } from "@heroui/react";
<Card>
<CardHeader>Header</CardHeader>
<CardBody>Body</CardBody>
<CardFooter>Footer</CardFooter>
</Card>v3: Compound Component Structure
In v3, Card uses a compound component pattern with explicit subcomponents:
import { Card } from "@heroui/react";
<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. Removed Props
The following props are no longer available in v3:
shadow- Use Tailwind CSS classes likeshadow-sm,shadow-md,shadow-lgradius- Use Tailwind CSS classes likerounded-lg,rounded-xl,rounded-fullfullWidth- Use Tailwind CSS classw-fullisHoverable- Use Tailwind CSS classes with hover statesisPressable- UseasChildprop with a button or link componentisBlurred- Use Tailwind CSS backdrop blur classesisFooterBlurred- Use Tailwind CSS backdrop blur classes on footerisDisabled- Handle disabled state manually with conditional renderingdisableAnimation- Animations are handled internallydisableRipple- Ripple effect removed in v3allowTextSelectionOnPress- Not applicableclassNames- UseclassNameprops on individual components
4. Variants
v2: No variant prop (used shadow/radius for styling)
v3: Has variant prop: transparent, default, secondary, tertiary, quaternary
Migration Examples
Basic Usage
import { Card, CardBody } from "@heroui/react";
export default function App() {
return (
<Card>
<CardBody>
<p>Make beautiful websites regardless of your design experience.</p>
</CardBody>
</Card>
);
}import { Card } from "@heroui/react";
export default function App() {
return (
<Card>
<Card.Content>
<p>Make beautiful websites regardless of your design experience.</p>
</Card.Content>
</Card>
);
}Card with Header, Body, and Footer
<Card>
<CardHeader>Header</CardHeader>
<CardBody>Body content</CardBody>
<CardFooter>Footer</CardFooter>
</Card><Card>
<Card.Header>
<Card.Title>Header</Card.Title>
</Card.Header>
<Card.Content>Body content</Card.Content>
<Card.Footer>Footer</Card.Footer>
</Card>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>Frontend Radio</Card.Title>
<Card.Description>Daily Mix • 12 Tracks</Card.Description>
</Card.Header>
<Card.Content>Content</Card.Content>
</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>Pressable Card
<Card
isPressable
shadow="sm"
onPress={() => console.log("pressed")}
>
<CardBody>Clickable card</CardBody>
</Card><Card
asChild
className="shadow-sm cursor-pointer"
>
<button onClick={() => console.log("pressed")}>
<Card.Content>Clickable card</Card.Content>
</button>
</Card>Card with Shadow
<Card shadow="lg">
<CardBody>Content</CardBody>
</Card><Card className="shadow-lg">
<Card.Content>Content</Card.Content>
</Card>Card with Radius
<Card radius="lg">
<CardBody>Content</CardBody>
</Card><Card className="rounded-lg">
<Card.Content>Content</Card.Content>
</Card>Full Width Card
<Card fullWidth>
<CardBody>Content</CardBody>
</Card><Card className="w-full">
<Card.Content>Content</Card.Content>
</Card>Hoverable Card
<Card isHoverable>
<CardBody>Content</CardBody>
</Card><Card className="transition-colors hover:bg-surface-secondary">
<Card.Content>Content</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>
<Card variant="tertiary">
<Card.Content>Content</Card.Content>
</Card>
<Card variant="transparent">
<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
│ ├── Card.Title (optional)
│ └── Card.Description (optional)
├── Card.Content
└── Card.Footer (optional)Breaking Changes 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
asChildprop with button/link instead ofisPressable - 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
Tips for Migration
- Start with structure: Convert component names first (
CardBody→Card.Content) - Add Title/Description: Use
Card.TitleandCard.Descriptionin headers for better semantics - Use Tailwind: Many removed props can be replaced with Tailwind utility classes
- Pressable cards: Wrap content in a button/link and use
asChildprop - Blur effects: Apply
backdrop-blur-mdclasses directly to footer elements - Variants: Use variants for semantic prominence rather than visual styling
Need Help?
For v3 Card features and API:
- See the API Reference
- Check interactive examples
For community support: