Marble UI
← Components

Card

Preview: Outline

Surface for grouped content: header, body and footer slots; outline, elevated or filled.

Import

import { Card, CardHeader, CardBody, CardFooter } from '@marbleui/ui'

Props

<Card>

PropTypeDefaultDescription
interactiveboolean—
variant'outline' | 'elevated' | 'filled''outline'

Also accepts HTML element props (278).

<CardHeader>

PropTypeDefaultDescription
title *requiredReactNode—
actionReactNode—
classNamestring—
descriptionReactNode—
level1 | 2 | 3 | 4 | 5 | 63Heading level for the title (default 3).

<CardBody>

No props of its own.

Also accepts HTML element props (278).

<CardFooter>

No props of its own.

Also accepts HTML element props (278).

Usage notes

Surface that groups related content into header, body and footer. For a single metric use Stat; for key–value pairs inside a card use DataList.

<Card variant="elevated">
  <CardHeader title="Pro plan" description="For growing teams." />
  <CardBody>$24 / seat / month</CardBody>
  <CardFooter><Button size="sm">Upgrade</Button></CardFooter>
</Card>
  • variant is outline (default), elevated or filled.
  • interactive only adds hover styling. It does not make the card focusable or clickable; for a clickable card add your own tabIndex, role and handler, or wrap a real link.
  • CardHeader renders title as an h3 by default; set level to fit the page outline. action takes a node placed at the right.
Example source · show
import { Badge } from '../badge'
import { Button } from '../button'
import { ProgressBar } from '../progress-bar'
import { Card, CardBody, CardFooter, CardHeader } from './card'

const Plan = ({ variant }: { variant: 'outline' | 'elevated' | 'filled' }) => (
  <Card variant={variant} className="w-80">
    <CardHeader title="Pro plan" description="For growing teams." action={<Badge tone="accent">Current</Badge>} />
    <CardBody className="flex flex-col gap-3">
      <div className="text-3xl font-semibold tracking-tight text-fg">
        $24<span className="text-sm font-normal text-fg-muted"> / seat / month</span>
      </div>
      <ProgressBar label="Seats used" value={7} maxValue={10} size="sm" valueLabel="7 of 10" />
    </CardBody>
    <CardFooter className="justify-end">
      <Button variant="ghost" size="sm">Compare plans</Button>
      <Button size="sm">Upgrade</Button>
    </CardFooter>
  </Card>
)

export const styles = {
  Outline: () => <Plan variant="outline" />,
  Elevated: () => <Plan variant="elevated" />,
  Filled: () => <Plan variant="filled" />,
  Interactive: () => (
    <div className="grid w-[34rem] grid-cols-2 gap-4">
      {['Website redesign', 'Mobile app'].map((t, i) => (
        <Card key={t} interactive tabIndex={0}>
          <CardHeader title={t} description={i ? '12 open issues' : '4 open issues'} />
          <CardBody>Updated {i ? '2 hours' : '5 minutes'} ago</CardBody>
        </Card>
      ))}
    </div>
  ),
}

Source: packages/ui/src/card/card.tsx

Catalog

Category
data-display
Priority
Foundation
Primitive
custom