# Card

A bordered surface that groups the content and actions of one subject.

```tsx
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@zenoxai/ui/components/card"

function CardDemo() {
  return (
    <Card className="w-full max-w-sm">
      <CardHeader>
        <CardTitle>Microsoft 365 connector</CardTitle>
        <CardDescription>
          Collects sign-in and audit logs every 5 minutes.
        </CardDescription>
      </CardHeader>
      <CardContent>
        <dl className="grid grid-cols-2 gap-y-2">
          <dt className="text-text-secondary">Last sync</dt>
          <dd className="text-right">4 minutes ago</dd>
          <dt className="text-text-secondary">Events today</dt>
          <dd className="text-right tabular-nums">182,340</dd>
        </dl>
      </CardContent>
    </Card>
  )
}
```

## Usage

```tsx
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@zenoxai/ui/components/card"

export function ConnectorCard() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Microsoft 365 connector</CardTitle>
        <CardDescription>
          Collects sign-in and audit logs every 5 minutes.
        </CardDescription>
      </CardHeader>
      <CardContent>Last sync 4 minutes ago</CardContent>
    </Card>
  )
}
```

Use a card for one subject: a connector, a settings group, a chart, a detail panel. The card sets
the padding, and its parts read it, so `CardHeader`, `CardContent` and `CardFooter` line up
without extra classes.

The header draws a divider under itself. To run the content straight on from the title, remove
it with `className="border-b-0 pb-0"` on `CardHeader`.

Use something else when:

- The card would show one figure with a label. Use [StatTile](/patterns/stat-tile).
- The content is a row in a list of similar records. Use [Item](/components/item).
- A section inside a card or a settings page needs a heading. Use
  [SectionHeading](/patterns/section-heading).

## With an action

`CardAction` puts a control at the top right of the header, aligned with the title. Use it for
the one action that applies to the whole card.

```tsx
import { PlusIcon } from "lucide-react"
import { Button } from "@zenoxai/ui/components/button"
import { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle } from "@zenoxai/ui/components/card"

function CardWithAction() {
  return (
    <Card className="w-full max-w-sm">
      <CardHeader>
        <CardTitle>Notification rules</CardTitle>
        <CardDescription>Who is paged for each severity.</CardDescription>
        <CardAction>
          <Button variant="outline" size="sm">
            <PlusIcon data-icon="inline-start" />
            Add rule
          </Button>
        </CardAction>
      </CardHeader>
      <CardContent>
        <ul className="grid gap-2">
          <li>Critical: on-call analyst, by phone</li>
          <li>High: SOC channel, by email</li>
        </ul>
      </CardContent>
    </Card>
  )
}
```

## With a footer

`CardFooter` has a top border and a muted background, and the card drops its bottom padding so
the footer sits flush with the edge. Put the form actions there, aligned to the end.

```tsx
import { Button } from "@zenoxai/ui/components/button"
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@zenoxai/ui/components/card"

function CardWithFooter() {
  return (
    <Card className="w-full max-w-sm">
      <CardHeader>
        <CardTitle>Retention</CardTitle>
        <CardDescription>
          Raw events older than this are deleted every night.
        </CardDescription>
      </CardHeader>
      <CardContent>
        <p>
          Events are kept for <span className="font-medium">90 days</span>.
          Alerts and reports are kept for the life of the tenant.
        </p>
      </CardContent>
      <CardFooter className="justify-end gap-2">
        <Button variant="ghost">Cancel</Button>
        <Button>Save changes</Button>
      </CardFooter>
    </Card>
  )
}
```

## Small

`size="sm"` reduces the padding from 16px to 12px and moves the title to the compact step
(14px, semibold; see [Typography](/foundations/typography#title-levels)). Use it for side panels
and grids of small cards.

```tsx
import { Button } from "@zenoxai/ui/components/button"
import { Card, CardAction, CardContent, CardHeader, CardTitle } from "@zenoxai/ui/components/card"

function CardSmall() {
  return (
    <Card size="sm" className="w-full max-w-xs">
      <CardHeader>
        <CardTitle>Asset owner</CardTitle>
        <CardAction>
          <Button variant="ghost" size="xs">
            Reassign
          </Button>
        </CardAction>
      </CardHeader>
      <CardContent className="grid gap-1">
        <span className="font-medium">Marina Rocha</span>
        <span className="text-text-secondary">Infrastructure team</span>
      </CardContent>
    </Card>
  )
}
```

## Accessibility

- `CardTitle` renders an `<h2>`, so cards show up in heading navigation. Inside a section that
  already has an `<h2>`, render a lower level: `<CardTitle render={<h3 />}>`.
- `CardDescription` is plain text. When it explains a control inside the card, link the two
  with `aria-describedby`.

## API reference

`import { ... } from "@zenoxai/ui/components/card"`

### Card

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| size | `"default" \| "sm"` | `default` | `sm` tightens the padding and gaps from 16px to 12px and steps the title down to text-sm, for dense grids. |

### CardHeader

No props of its own.

### CardFooter

No props of its own.

### CardTitle

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, {}>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |

### CardAction

No props of its own.

### CardDescription

No props of its own.

### CardContent

No props of its own.

