1
ComponentsData Display

Card

Card groups related content, actions, forms, or framed data into a clear surface.

Purpose

Card groups related content, actions, forms, or framed data into a clear surface. It is not a general page-layout primitive.

Structured card

Workspace
Team usage this month.
84%Healthy
x
Updated 4 minutes ago
import { Card, CardHeader, CardTitle, CardDescription, CardAction, CardPanel, CardFooter } from "@/components/ui/card";

export function Example() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Workspace</CardTitle>
        <CardDescription>Team usage this month.</CardDescription>
        <CardAction>
          <Button size="sm" variant="outline">Open</Button>
        </CardAction>
      </CardHeader>
      <CardPanel>...</CardPanel>
      <CardFooter>Updated now</CardFooter>
    </Card>
  );
}

Installation

With the Siteplane registry alias configured, add the component and import the installed source from your app.

CLI

pnpm dlx shadcn@4.16.1 add @siteplane/card

Import

import { Card, CardAction, CardContent, CardDescription, CardFooter, CardFrame, CardFrameAction, CardFrameDescription, CardFrameHeader, CardFrameTitle, CardHeader, CardPanel, CardTitle } from "@/components/ui/card";

Need the machine-readable source metadata? View registry JSON.

Usage

Card groups related content. Use the header, panel, action and footer slots instead of nested card stacks.

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

export function Example() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Workspace</CardTitle>
        <CardDescription>Team usage this month.</CardDescription>
        <CardAction>
          <Button size="sm" variant="outline">Open</Button>
        </CardAction>
      </CardHeader>
      <CardPanel>...</CardPanel>
      <CardFooter>Updated now</CardFooter>
    </Card>
  );
}

Examples

Anatomy, header actions, form composition and CardFrame stacks are compositions of the same slots. CardContent is an exported alias for CardPanel.

Basic card

Workspace
Shared project context for the team.
3 active projectsLast updated today
<Card>
  <CardHeader>
    <CardTitle>Workspace</CardTitle>
    <CardDescription>Shared project context for the team.</CardDescription>
  </CardHeader>
  <CardPanel>...</CardPanel>
  <CardFooter>
    <Button variant="outline">Open workspace</Button>
  </CardFooter>
</Card>

Header action

Billing
Current plan and seat usage.
Pro plan12 of 20 seats used
<Card>
  <CardHeader>
    <CardTitle>Billing</CardTitle>
    <CardDescription>Current plan and seat usage.</CardDescription>
    <CardAction>
      <Button variant="outline">Manage</Button>
    </CardAction>
  </CardHeader>
  <CardPanel>...</CardPanel>
</Card>

Form in card

Create project
Deploy your new project in one click.

This will take a few seconds to complete.

<Card>
  <CardHeader>
    <CardTitle>Create project</CardTitle>
    <CardDescription>Deploy your new project in one click.</CardDescription>
  </CardHeader>
  <CardPanel>
    <Form onSubmit={handleSubmit}>
      <Field>
        <FieldLabel>Name</FieldLabel>
        <Input placeholder="Name of your project" type="text" />
      </Field>
      <Field>
        <FieldLabel>Framework</FieldLabel>
        <Select defaultValue="next" items={frameworkOptions}>
          <SelectTrigger aria-label="Framework"><SelectValue /></SelectTrigger>
          <SelectPopup>
            {frameworkOptions.map(({ label, value }) => (
              <SelectItem key={value} value={value}>{label}</SelectItem>
            ))}
          </SelectPopup>
        </Select>
      </Field>
      <Button className="w-full" type="submit">Deploy</Button>
    </Form>
  </CardPanel>
  <CardFooter>
    <div className="flex gap-1 text-muted-foreground text-xs">
      <CircleAlertIcon className="size-3 h-lh shrink-0" />
      <p>This will take a few seconds to complete.</p>
    </div>
  </CardFooter>
</Card>

Table in CardFrame

ProjectStatusTeamBudget
Website RedesignPaidFrontend Team$12,500
Mobile AppUnpaidMobile Team$8,750
API IntegrationPendingBackend Team$5,200
Total Budget$26,450
<CardFrame>
  <Table variant="card">
    <TableHeader>
      <TableRow>
        <TableHead>Project</TableHead>
        <TableHead>Status</TableHead>
        <TableHead>Team</TableHead>
        <TableHead className="text-right">Budget</TableHead>
      </TableRow>
    </TableHeader>
    <TableBody>
      {projectRows.map((project) => (
        <TableRow key={project.project}>
          <TableCell className="font-medium">{project.project}</TableCell>
          <TableCell>
            <Badge variant={project.variant}>{project.status}</Badge>
          </TableCell>
          <TableCell>{project.team}</TableCell>
          <TableCell className="text-right">{project.budget}</TableCell>
        </TableRow>
      ))}
    </TableBody>
    <TableFooter>
      <TableRow>
        <TableCell colSpan={3}>Total Budget</TableCell>
        <TableCell className="text-right">$26,450</TableCell>
      </TableRow>
    </TableFooter>
  </Table>
</CardFrame>

Card frame slots

CardFrame slots wrap stacked cards with a shared header, action and footer.

Integrations
Connected services for this workspace.
GitHubConnected
SlackNot connected
1 of 2 services connected
<CardFrame>
  <CardFrameHeader>
    <CardFrameTitle>Integrations</CardFrameTitle>
    <CardFrameDescription>Connected services for this workspace.</CardFrameDescription>
    <CardFrameAction>
      <Button size="sm" variant="outline">Add</Button>
    </CardFrameAction>
  </CardFrameHeader>
  <Card>
    <CardPanel>GitHub</CardPanel>
  </Card>
  <Card>
    <CardPanel>Slack</CardPanel>
  </Card>
  <CardFrameFooter>1 of 2 services connected</CardFrameFooter>
</CardFrame>

Render prop

The render prop swaps the underlying element while keeping card styling.

Render prop
Render as a semantic section when needed.
<Card render={<section />}>
  <CardHeader>
    <CardTitle>Render prop</CardTitle>
    <CardDescription>Render as a semantic section when needed.</CardDescription>
  </CardHeader>
  <CardPanel>...</CardPanel>
</Card>

API Reference

The reference lists the source-owned exports and props that are easy to miss in visual examples. Inherited Base UI props remain available unless the wrapper narrows them.

  • Compose CardHeader, CardTitle, CardDescription, CardAction, CardPanel, and CardFooter as needed.
  • CardContent is a compatibility alias for CardPanel; use CardPanel in new code.
  • CardFrame and its slots support framed stacks and table-like content.
  • Adding className="border-b" to CardHeader or className="border-t" to CardFooter switches the adjacent CardPanel to full vertical padding for a visually separated section.
  • The root render prop may change the underlying semantic element.

Motion

Component motion uses the shared Siteplane motion contract. See the global motion guide for provider setup, tokens and reduced-motion behavior.

  • Card is a static container with no mount or exit animation.
  • Interactive children use their own primitive motion; do not animate Card locally.
  • Preserve native radius, clipping, surface, shadow, and slot classes.

Accessibility

  • Card is visual grouping and does not replace semantic lists, tables, forms, headings, or landmarks.
  • Keep titles meaningful in their surrounding document structure.
  • Card actions remain real Button or link controls with visible focus.
  • If render changes the root element, retain semantics appropriate to the content.

Implementation Guidance

  • Use existing Card and CardFrame slots instead of wrapper primitives.
  • Use CardPanel in new code and treat CardContent only as a compatibility alias.
  • Do not use Card as a generic layout box.

On This Page