Skip to content
shadcn.io is not affiliated with official shadcn/ui

Shadcn Card for React and Tailwind

A surface for a single subject: header, media, body, and footer.

Login to your account

Enter your email and check your inbox

Installation

bunx --bun shadcn@latest add https://kit.dev/r/card.json

Anatomy

Card
├── CardMedia
├── CardHeader
│   ├── CardTitle
│   ├── CardDescription
│   └── CardAction
├── CardContent
└── CardFooter

Keep CardHeader, CardContent, and CardFooter as direct children of Card so padding and --space stay aligned.

Usage

import {
  Card,
  CardAction,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardMedia,
  CardTitle,
} from "@/components/ui/card";
<Card>
  <CardHeader title="Title" description="Description">
    <CardAction />
  </CardHeader>
  <CardContent>Content</CardContent>
  <CardFooter>Footer</CardFooter>
</Card>

Title and description

CardHeader supports two patterns. Do not mix title / description props with CardTitle / CardDescription children.

Using props

<CardHeader title="Card Title" description="Card description">
  <CardAction />
</CardHeader>

A string-only child of CardHeader is wrapped in CardTitle when title is omitted.

Using components

Use CardTitle and CardDescription when you need extra nodes or markup.

<CardHeader>
  <CardTitle>Card Title</CardTitle>
  <CardDescription>Card description</CardDescription>
  <CardAction />
</CardHeader>

CardTitle renders an h2. CardDescription renders a p. Use asChild if you need a different heading level.

Examples

Product card

CardMedia with variant="image" sits flush to the top (pt-0 on the card). Give the image an alt.

Icon card

variant="icon" sizes child SVGs to size-4. Decorative icons should be aria-hidden="true".

asChild merges card styles onto a single child. Do not put buttons inside a link card.

Custom spacing

[--space:--spacing(n)] on Card sets internal padding. Default is --spacing(6).

md:[--space:--spacing(6)] lg:[--space:--spacing(8)]

Guides

Spacing

--space is defined on the root and used as py-(--space) and px-(--space) on sections. A footer adds its own py-(--space) and the root drops bottom padding (has-data-[slot=card-footer]:pb-0). Image media drops top padding (has-data-[variant=image]:pt-0).

CardAction

CardAction sits in the header’s end column and spans the title/description rows. Place it as a child of CardHeader.

asChild

<Card asChild>
  <a href="/docs">
    <CardHeader title="Docs" description="API and examples." />
  </a>
</Card>

API Reference

shadcn.io Card is composed div / h2 / p (Ark factory), not a Zag machine. There is no context hook or root provider.

asChild merges props onto a single child element.

Card

Root. Renders a div.

PropTypeDefaultDescription
asChildbooleanfalseRender the child element instead of a div.
classNamestring-Class names on the root. Set [--space:] here.
AttributeDescription
data-slotcard
CSS variableDefaultDescription
--space--spacing(6)Horizontal padding of sections and vertical padding of the root/footer.

CardMedia

Media strip. Renders a div.

PropTypeDefaultDescription
variant"default" | "icon" | "image""default"icon sizes SVGs. image is full-bleed at the top.
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the media.
AttributeDescription
data-slotcard-media
data-variant"default", "icon", or "image"

CardHeader

Header grid. Renders a div. With CardAction, the grid is 1fr auto.

PropTypeDefaultDescription
titlestring-Renders CardTitle. Do not also pass CardTitle.
descriptionstring-Renders CardDescription.
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the header.
AttributeDescription
data-slotcard-header

CardTitle

Title. Renders an h2.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child (h3, Link, …).
classNamestring-Class names on the title.
AttributeDescription
data-slotcard-title

CardDescription

Supporting text. Renders a p.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the description.
AttributeDescription
data-slotcard-description

CardAction

End-aligned slot in the header. Renders a div.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the action.
AttributeDescription
data-slotcard-action

CardContent

Body. Renders a div.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the content.
AttributeDescription
data-slotcard-content

CardFooter

Footer with a top border and muted background. Renders a div.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the footer.
AttributeDescription
data-slotcard-footer

cardMediaVariants

Exported tv() recipe. Same variant key as CardMedia.

CardHeaderProps / CardMediaProps

Props of CardHeader and CardMedia.

Accessibility

Card is a layout surface, not a composite widget.

  • CardTitle is an h2. Use asChild with h3 (or another level) if the page outline needs it.
  • Images: meaningful alt, or alt="" if decorative (for example a link card whose title is already in text).
  • Decorative icons: aria-hidden="true".
  • A whole-card link uses asChild on Card. Do not nest buttons or other links inside it.

Keyboard support

The card is not interactive. If asChild renders a link or button, that control’s keys apply (Tab, Enter). Controls inside the card (inputs, buttons) stay in the normal tab order.