Card (.ods-card) is the base container primitive. It ships unopinionated about internal layout — compose it with CardHeader/CardTitle/CardBody/CardFooter for the common header-body-footer shape, or use the base Card alone for a plain bordered surface.
Installation
HTML — already included if you loaded the 3 stylesheets. See the Installation guide.
React
npm install @operant/ui
@operant/ui is currently a monorepo workspace package, not yet published to the public npm registry.
Usage
HTML
<div class="ods-card">
<div class="ods-card-header">
<div class="ods-card-title">Deploy pipeline</div>
<span class="ods-badge -success">Healthy</span>
</div>
<div class="ods-card-body">Last run completed 4 minutes ago across 3 regions.</div>
<div class="ods-card-footer">
<button type="button" class="ods-btn -ghost -sm">View trace</button>
</div>
</div>
React
import { Badge, Button, Card, CardBody, CardFooter, CardHeader, CardTitle } from "@operant/ui";
export default function Example() {
return (
<Card style={{ width: 320 }}>
<CardHeader>
<CardTitle>Deploy pipeline</CardTitle>
<Badge variant="success">Healthy</Badge>
</CardHeader>
<CardBody>Last run completed 4 minutes ago across 3 regions.</CardBody>
<CardFooter>
<Button variant="ghost" size="sm">
View trace
</Button>
</CardFooter>
</Card>
);
}
Examples
Basic
The default Card has a flat surface, a hairline border, and no shadow — appropriate for cards sitting in a grid where every card is equally "at rest."
<div class="ods-card" style="width: 320px">
<div class="ods-card-body">A plain card with body content only.</div>
</div>
<Card style={{ width: 320 }}>
<CardBody>A plain card with body content only.</CardBody>
</Card>
Elevated
-elevated adds --shadow-sm to lift the card above the page — use for a card that should read as "on top of" its surroundings (e.g. a floating summary panel), not for every card in a dense list.
<div class="ods-card -elevated" style="width: 320px">
<div class="ods-card-body">
Elevated cards use <code>--shadow-sm</code> to sit above the page.
</div>
</div>
<Card elevated style={{ width: 320 }}>
<CardBody>Elevated cards use `--shadow-sm` to sit above the page.</CardBody>
</Card>
Interactive
-interactive sets cursor: pointer and animates border-color/box-shadow on hover — use when the entire card is a click target (e.g. it opens a run detail page).
<div class="ods-card -interactive" style="width: 320px">
<div class="ods-card-body">Click anywhere on this card to open the run.</div>
</div>
<Card interactive style={{ width: 320 }}>
<CardBody>Click anywhere on this card to open the run.</CardBody>
</Card>
API Reference
<Card>
Renders a <div class="ods-card">.
| Prop | Type | Default | Description |
|---|---|---|---|
elevated | boolean | false | Adds -elevated (--shadow-sm). |
interactive | boolean | false | Adds -interactive (pointer cursor, hover border/shadow transition). |
className | string | — | Additional classes merged onto the card. |
children | ReactNode | — | Card content — typically CardHeader/CardBody/CardFooter. |
All other native <div> attributes are forwarded.
<CardHeader> / <CardTitle> / <CardBody> / <CardFooter>
Each is a thin wrapper with no props beyond native <div> attributes:
| Component | Class | Notes |
|---|---|---|
CardHeader | .ods-card-header | Flex row, bottom hairline border. Typically holds CardTitle + a Badge. |
CardTitle | .ods-card-title | --fs-lg / --fw-semibold heading text. |
CardBody | .ods-card-body | Padded content area. |
CardFooter | .ods-card-footer | Flex row, top hairline border. Typically holds action Buttons. |
HTML-side modifiers: .ods-card (base) + optional -elevated and/or -interactive.
Accessibility
Cardrenders a plain<div>with no implicit role or focusability. If a card is-interactiveand the entire surface is clickable, make sure the click target is also reachable by keyboard — e.g. wrap the card in a real<a>/<button>, or addtabIndex={0}plus akeydownhandler for Enter/Space, and an appropriaterole(linkorbutton).- Don't rely on
-interactive's hover styling alone to signal clickability — pair it with a visible affordance (a chevron, "View trace" link, etc.) inside the card. CardTitleis a styled<div>, not a heading element — use a real<h2>–<h6>inside it (or as a sibling) if the card title should participate in the page's heading outline.