1. Documentation
  2. Layout
  3. Card
ReadmenpmGitHub
  • Introduction
  • Installation
  • Theming
  • Icons
  • Accordion
  • Card
  • Scroll Area
  • Separator
  • Sidebar
  • Field
  • Label
  • Input
  • Textarea
  • Number Field
  • OTP Field
  • Select
  • Combobox
  • Checkbox
  • Radio
  • Switch
  • Slider
  • Toggle
  • Calendar
  • Date Picker
  • File Upload
  • Button
  • Copy Button
  • Dropdown
  • Command
  • Tabs
  • Breadcrumb
  • Pagination
  • Tree
  • Table
  • Data Table
  • Stat
  • Timeline
  • Avatar
  • Status Bar
  • Badge
  • Meter
  • Empty
  • Skeleton
  • Spinner
  • Toast
  • Dialog
  • Sheet
  • Popover
  • Tooltip
  • Text
  • Kbd
  • Code Block
  • Utilities
  • Design rules

Card

A surface with four elevations, plus header, body and footer slots that keep their own padding.

Loading documentation…

Accordion< PreviousScroll AreaNext >

Powered by heyo

On this page

UsageVariantsThe header is a rowBody onlyThe footer is for actionsPropertiesCardCardHeader, CardBody, CardFooterCardTitle and CardDescription

Deployments

Last 3 builds of acme-api

CommitBranchDuration
a1b2c3dmain42s
9f8e7d6main38s
4c5b6a7fix/cors12s
<Card variant="raised"><CardHeader>  <div className="flex flex-col gap-0.5">    <CardTitle>Deployments</CardTitle>    <CardDescription>Last 3 builds of acme-api</CardDescription>  </div>  <Button size="sm" variant="ghost" icon={IconExternalLink}>    View all  </Button></CardHeader><CardBody className="p-0">  <Table interactive>    <Table.Head>      <Table.Row>        <Table.Header>Commit</Table.Header>        <Table.Header>Branch</Table.Header>        <Table.Header align="end">Duration</Table.Header>      </Table.Row>    </Table.Head>    <Table.Body>      {builds.map(({ sha, branch, time }) => (        <Table.Row key={sha}>          <Table.Cell><Code>{sha}</Code></Table.Cell>          <Table.Cell className="text-heyo-subtle">{branch}</Table.Cell>          <Table.Cell align="end" numeric>{time}</Table.Cell>        </Table.Row>      ))}    </Table.Body>  </Table></CardBody><CardFooter>  <Button size="sm" variant="ghost">Cancel</Button>  <Button size="sm" variant="primary" icon={IconRocket}>Redeploy</Button></CardFooter></Card>

Card is the box every grouped surface in an application is built from. The parts are independent: a card can be a header and a body, a body alone, or all three. Seams are only drawn where something actually follows, so a header without a body carries no stray rule.

Every slot keeps its own padding, which is what lets a table or a list sit flush inside one — drop p-0 on CardBody and the rows run edge to edge.

Usage

tsx
import { Card, CardBody, CardHeader, CardTitle } from "@heyo-sh/heyo-ui";<Card>  <CardHeader>    <CardTitle>Usage</CardTitle>  </CardHeader>  <CardBody>142,318 requests this month.</CardBody></Card>;

Variants

flat is the default and the right answer in a dense interface: a hairline is enough to separate a surface from the page. raised adds a real edge and a whisper of shadow for something that floats. recessed is a well — logs, diffs, empty states. plain keeps only the layout. Hierarchy comes from the surface, not from a border.

variant="plain"

Same padding, different elevation.

plain

Hierarchy comes from the surface, not from a border.

variant="flat"

Same padding, different elevation.

flat

Hierarchy comes from the surface, not from a border.

variant="raised"

Same padding, different elevation.

raised

Hierarchy comes from the surface, not from a border.

variant="recessed"

Same padding, different elevation.

recessed

Hierarchy comes from the surface, not from a border.

<Card variant="flat"><CardHeader>  <div className="flex flex-col gap-0.5">    <CardTitle>variant="flat"</CardTitle>    <CardDescription>Same padding, different elevation.</CardDescription>  </div>  <Badge variant="outline" size="sm">flat</Badge></CardHeader><CardBody>  <Text size="sm" tone="subtle">    Hierarchy comes from the surface, not from a border.  </Text></CardBody></Card>

The header is a row

CardHeader is a flex row with justify-between, so a title on the left and a control on the right need no extra wrapper. Group the title and description in one element when both are present.

Environment variables

No variables yet.

<Card><CardHeader>  <CardTitle>Environment variables</CardTitle>  <Button size="sm" icon={IconPlus}>Add</Button></CardHeader><CardBody>  <Text size="sm" tone="subtle">No variables yet.</Text></CardBody></Card>

Body only

A card does not need three slots. One CardBody is the whole component when the content is a single figure.

Requests today

1.24M

<Card><CardBody className="flex items-baseline justify-between">  <Text size="sm" tone="subtle" className="flex items-center gap-1.5">    <IconTrendingUp className="size-4 shrink-0" />    Requests today  </Text>  <Text size="xl" weight="medium" className="tabular-nums">1.24M</Text></CardBody></Card>

The footer is for actions

CardFooter sits on the elevated surface and right-aligns its children, which is where a card's actions belong. It is not a second body — long content in a footer means the card wants another section instead.

Pairs well with

Stat is borderless by default so it can live inside a card. Empty fills a card body that has nothing in it yet.

Properties

Card

variant"flat" | "raised" | "recessed" | "plain"optional

The surface treatment. It defaults to flat.

classNamestringoptional

Merged through tailwind-merge, so a different radius or width is one class.

childrenReactNodeoptional

Usually CardHeader, CardBody and CardFooter, in that order.

CardHeader, CardBody, CardFooter

childrenReactNodeoptional

CardHeader lays its children out as a row with the last item pushed right. CardBody is the content column. CardFooter right-aligns actions on the elevated surface.

classNamestringoptional

Merged into the respective part — p-0 on CardBody is how a table or a list sits flush. Every part also carries a data-slot (card-header, card-body, card-footer) for global overrides.

CardTitle and CardDescription

childrenReactNodeoptional

CardTitle renders an <h3> at 13px medium; CardDescription renders a 12px muted paragraph. Both have their margins reset.