27.5k

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 Componentv3 ComponentNotes
CardHeaderCard.HeaderSame functionality
CardBodyCard.ContentRenamed
CardFooterCard.FooterSame functionality
-Card.TitleNew subcomponent for header titles
-Card.DescriptionNew subcomponent for header descriptions

3. Removed Props

The following props are no longer available in v3:

  • shadow - Use Tailwind CSS classes like shadow-sm, shadow-md, shadow-lg
  • radius - Use Tailwind CSS classes like rounded-lg, rounded-xl, rounded-full
  • fullWidth - Use Tailwind CSS class w-full
  • isHoverable - Use Tailwind CSS classes with hover states
  • isPressable - Use asChild prop with a button or link component
  • isBlurred - Use Tailwind CSS backdrop blur classes
  • isFooterBlurred - Use Tailwind CSS backdrop blur classes on footer
  • isDisabled - Handle disabled state manually with conditional rendering
  • disableAnimation - Animations are handled internally
  • disableRipple - Ripple effect removed in v3
  • allowTextSelectionOnPress - Not applicable
  • classNames - Use className props 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>
  <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>
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

  1. Component Structure: Must use compound components instead of separate components
  2. CardBody → Card.Content: Component renamed
  3. New Subcomponents: Card.Title and Card.Description for structured headers
  4. Props Removed: Many styling props removed; use Tailwind CSS classes
  5. Pressable Cards: Use asChild prop with button/link instead of isPressable
  6. Blur Effects: Use Tailwind backdrop-blur-* classes instead of props
  7. Variants: New variant system for semantic prominence levels
  8. ClassNames Removed: Use className props on individual components

Tips for Migration

  1. Start with structure: Convert component names first (CardBodyCard.Content)
  2. Add Title/Description: Use Card.Title and Card.Description in headers for better semantics
  3. Use Tailwind: Many removed props can be replaced with Tailwind utility classes
  4. Pressable cards: Wrap content in a button/link and use asChild prop
  5. Blur effects: Apply backdrop-blur-md classes directly to footer elements
  6. Variants: Use variants for semantic prominence rather than visual styling

Need Help?

For v3 Card features and API:

For community support: