Skip to content
Component installs need the registry setup
VegaStack Design

Card

Displays a card with header, content, and footer — one spacing variable drives every section gap and part inset.

Status
stable
Since
0.1.0
Accessibility pattern
plain container, no implicit role

Last updated

Login to your account
Enter your email below to login to your account

Install

Configure registry credentials first using the Quickstart. Before copying this item or any transitive registry dependency, verify the signed manifest and save the exact bytes for Card before installation. Retain the digest printed by this command.

pnpm exec vegastack-design verify card

Install with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.

pnpm dlx shadcn@4.21.0 add @vegastack/card

Run the exact offline --post-write command printed by the preflight, using its saved item path and independently retained --expected-integrity digest. Use the saved preflight for every transitive registry dependency too; stop on any mismatch before using the components.

Usage

import {
  Card,
  CardAction,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";

<Card>
  <CardHeader>
    <CardTitle>Card Title</CardTitle>
    <CardDescription>Card Description</CardDescription>
    <CardAction>Card Action</CardAction>
  </CardHeader>
  <CardContent>
    <p>Card Content</p>
  </CardContent>
  <CardFooter>
    <p>Card Footer</p>
  </CardFooter>
</Card>;
Login to your account
Enter your email below to login to your account

Anatomy

Card — data-slot="card"
CardAction — data-slot="card-action"
CardContent — data-slot="card-content"
CardDescription — data-slot="card-description"
CardFooter — data-slot="card-footer"
CardHeader — data-slot="card-header"
CardTitle

Examples

Composition

CardHeader holds the title, the description and the action; CardContent holds the body; CardFooter holds what closes the card. CardAction places itself in the top corner of the header grid, so it is written inside CardHeader rather than floated over the card.

Card Title
Card Description
Card Action

Card Content

Card Footer

Size

Use size="sm" to set the card to the small size, which uses smaller spacing throughout.

Scheduled reports
Weekly snapshots. No more manual exports.
  • Choose a schedule (daily, or weekly).
  • Send to channels or specific teammates.
  • Include charts, tables, and key metrics.

Variant

variant="outline" keeps the border and drops the fill, so the card reads as a bordered group on the page rather than a raised panel — a record's side-panel cards (Record Aside) and dashboard cards. default is the filled card.

Default
A raised surface with the card fill.
Open deals: 12
Outline
The border only, on the page.
Open deals: 12

Spacing

In addition to the size prop, the --card-spacing CSS variable controls the gap between sections and the inset of every card part. Set it on the root and every part follows.

Use negative margins with -mx-(--card-spacing) to take content edge to edge while keeping it aligned with the card inset. When that content sits above a footer, add -mb-(--card-spacing) to CardContent to remove the section gap.

12px
Section gap and part inset.

Footer

16px
Section gap and part inset.

Footer

24px
Section gap and part inset.

Footer

Terms of Service
Review the terms before accepting the agreement.

These terms govern your use of the workspace, including access to shared documents, project files, and collaboration tools.

You are responsible for the content you upload and for ensuring that your team has the appropriate permissions to view or edit it.

By continuing, you agree to keep your account credentials secure and to follow your organization's acceptable use policies.

Image

Add an image before the card header to create a card with an image. The root drops its top padding and rounds the first and last image for you.

Featured
Design systems meetup
A practical talk on component APIs, accessibility, and shipping faster.

RTL

The card is written in logical properties throughout, so a right-to-left document mirrors the header grid, the action corner and the part insets without any extra work.

Login to your account
Enter your email below to login to your account
تسجيل الدخول إلى حسابك
أدخل بريدك الإلكتروني أدناه لتسجيل الدخول إلى حسابك

As a heading

CardTitle renders a div by default. Pass render to make it the real heading at the level the page needs; the classes and the data-slot stay the same.

<CardTitle render={<h3 />}>Usage this month</CardTitle>

Usage this month

Seats in use across the workspace

12 of 20

API Reference

Card

PropTypeDefaultDescription
size"default" | "sm"—
variant"default" | "outline"—

CardHeader

CardHeader adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

CardTitle

CardTitle adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

CardDescription

CardDescription adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

CardAction

CardAction adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

CardContent

CardContent adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

CardFooter

CardFooter adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

Accessibility

  • Every part renders a plain div with no implicit role, so a card adds nothing to the accessibility tree on its own. Give it the landmark or heading it deserves — pass render={<h2 />} to CardTitle, or wrap the card in a section with an accessible name.
  • CardTitle is styled, not semantic, until it is given render (API-22). A page of cards still needs a real heading level so the document outline reads correctly.
  • Keep the reading order the visual order: CardAction sits in the top corner but is written inside CardHeader, after the title and description, which is where a keyboard reaches it.
  • An image placed before the header is decorative in these examples and takes an empty alt. Give it a real description when it carries information the copy does not.
ContractStates tested
Behaviourdefault
Accessibilitynative-or-base-ui-semantics, browser-accessibility-test
Visualdefault

Do / Don't

Do
Set --card-spacing on the root when a card needs a different rhythm.
Don't
Re-pad CardHeader, CardContent and CardFooter one by one to fake a denser card.

Deviations

Upstream's file plus packages/ui/upstream/patches/card.patch. Every hunk:

  • BRD-1 — the card draws a real 1px border border-border instead of upstream's ring-1 ring-foreground/10 box-shadow outline. A border survives forced colours and matches Elevation. It sits inside the box, so overflow-hidden clips a full-bleed image at the border's inner edge and the corners stay concentric.
  • API-22 — CardTitle renders through Base UI's useRender, so it takes render and the heading level is set on the part. The default div, the data-slot and the classes are upstream's.
  • API-16 — "use client" is added: useRender calls React.useRef internally, so the module needs the client boundary to import in a Server Component.
  • DOC-2 — cn is imported from @vegastack/design.

Nothing else. The --card-spacing mechanism, the seven parts and every other class are upstream's, byte for byte; the remaining diff is the repository formatter reflowing the file.

On this page