# Card

> A contained surface for related content, with header, media, content and footer parts.

Category: Data display · Status: stable · Package: @bindshq/stance-react@0.1.1 · Docs: https://stanceui.com/components/card

Use Card to group information about one subject, such as a template, contract or integration. Cards can be static, contain actions, or be fully clickable through CardLink. Avoid nesting cards inside cards.

## Import

```tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, CardMedia, CardLink } from '@bindshq/stance-react';
```

Styles are imported once per app: `@bindshq/stance-tokens/css` and `@bindshq/stance-react/styles.css`.

## Examples

### Basic

```tsx
import { Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@bindshq/stance-react';

export function Basic() {
  return (
    <Card style={{ maxWidth: 380 }}>
      <CardHeader
        actions={
          <Badge tone="success" dot>
            Live
          </Badge>
        }
      >
        <CardTitle>Exchange relay</CardTitle>
        <CardDescription>Deploys signatures to Microsoft 365 mailboxes.</CardDescription>
      </CardHeader>
      <CardContent>Last sync 4 minutes ago · 312 mailboxes</CardContent>
      <CardFooter>
        <Button variant="ghost" size="sm">
          View logs
        </Button>
        <Button size="sm">Sync now</Button>
      </CardFooter>
    </Card>
  );
}
```

### Variants

```tsx
import { Card, CardDescription, CardTitle } from '@bindshq/stance-react';

export function Variants() {
  return (
    <div
      style={{
        display: 'grid',
        gap: 16,
        gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
        width: '100%',
      }}
    >
      {(['outline', 'elevated', 'filled'] as const).map((v) => (
        <Card key={v} variant={v}>
          <CardTitle>{v[0]!.toUpperCase() + v.slice(1)}</CardTitle>
          <CardDescription>3 contracts awaiting review</CardDescription>
        </Card>
      ))}
    </div>
  );
}
```

### Clickable card

CardLink stretches its hit area across the card. Header actions stay clickable above it.

```tsx
import { Button, Card, CardDescription, CardHeader, CardLink, CardTitle, Icon } from '@bindshq/stance-react';

export function Interactive() {
  return (
    <Card interactive style={{ maxWidth: 380 }}>
      <CardHeader
        actions={
          <Button size="xs" variant="ghost" aria-label="Duplicate Executive template">
            <Icon name="copy" />
          </Button>
        }
      >
        <CardTitle>
          <CardLink href="#executive">Executive</CardLink>
        </CardTitle>
        <CardDescription>Used by 6 people · edited last week</CardDescription>
      </CardHeader>
    </Card>
  );
}
```

### With media

```tsx
import { Badge, Button, Card, CardDescription, CardFooter, CardHeader, CardMedia, CardTitle } from '@bindshq/stance-react';

export function WithMedia() {
  return (
    <Card style={{ maxWidth: 340 }}>
      <CardMedia ratio="16 / 7" aria-hidden="true">
        <svg viewBox="0 0 320 140" preserveAspectRatio="xMidYMid slice">
          <rect width="320" height="140" fill="currentColor" opacity="0.06" />
          <rect x="24" y="36" width="120" height="10" rx="5" fill="currentColor" opacity="0.5" />
          <rect x="24" y="56" width="180" height="8" rx="4" fill="currentColor" opacity="0.25" />
          <rect x="24" y="72" width="150" height="8" rx="4" fill="currentColor" opacity="0.25" />
        </svg>
      </CardMedia>
      <CardHeader>
        <CardTitle>Minimal</CardTitle>
        <CardDescription>A clean, single-column signature layout.</CardDescription>
      </CardHeader>
      <CardFooter align="between">
        <Badge>Gallery</Badge>
        <Button size="sm" variant="outline">
          Use template
        </Button>
      </CardFooter>
    </Card>
  );
}
```

## API reference

| Component | Prop | Type | Default | Description |
| --- | --- | --- | --- | --- |
| Card | `variant` | `'outline' \| 'elevated' \| 'filled'` | `'outline'` | Surface treatment. |
| Card | `padding` | `'none' \| 'sm' \| 'md' \| 'lg'` | `'md'` | Inner padding. |
| Card | `interactive` | `boolean` | `false` | Make the card a click target through its CardLink. |
| Card | `asChild` | `boolean` | `false` | Render as the child element, e.g. <article>. |
| CardHeader | `actions` | `ReactNode` | None | Trailing header actions. |
| CardTitle | `level` | `2 \| 3 \| 4 \| 5 \| 6` | `3` | Heading level. |
| CardFooter | `align` | `'start' \| 'end' \| 'between'` | `'end'` | Footer alignment. |
| CardMedia | `ratio` | `number \| string` | `'16 / 9'` | Aspect ratio of the media area. |
| CardLink | `asChild` | `boolean` | `false` | Render your router link as the card link. |

## Accessibility

- CardTitle renders a real heading; choose a level that fits the page outline.
- Clickable cards use one real link (CardLink) rather than onClick on a div. Its accessible name is the title, so screen-reader link lists stay concise.
- Buttons and links in an interactive card are lifted above the stretched link, so they stay independently operable.
- The focus ring is drawn around the whole card while its link has keyboard focus.

## Keyboard

| Keys | Action |
| --- | --- |
| `Tab` | Moves to the card link, then to any actions in the card. |

## Guidelines

**Do**

- Keep one primary action per card.
- Use asChild with <article> for self-contained content.

**Don’t**

- Wrap a whole card in <a> when it contains buttons.
- Nest cards.

## Related

- https://stanceui.com/components/stat-card
- https://stanceui.com/components/list
- https://stanceui.com/components/empty-state
