Pro--% off in--d : --h : --m : --s
HeroUI

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

3. Prop Changes

v2 Propv3 LocationNotes
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>
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

  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 a button or link inside Card 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

On this page