Behive Tech Registry

Card

v0.4.0

A surface container with configurable padding and an optional header (icon + title + an `action` slot).

pnpm add @behivetech/atoms.card

A surface container with configurable padding and an optional header (icon + title + an action slot).

Usage

The action slot is freeform — pass a close button, a menu, multiple buttons, or nothing. If icon, title, and action are all omitted, no header is rendered and children render directly in the card (unchanged from a plain Card). When a header is present, padding applies to the body instead of the whole card, so the header can span edge-to-edge with its own fixed padding.

Heading level

title renders inside an h1–h6 tag (not a span) so it takes its correct place in the page's heading outline — set via headingLevel, which defaults to 3. The default assumes the common case: a page's own h1, sections within it titled h2, and a Card nested inside one of those sections landing at h3. Override it when a card sits at a different depth — e.g. headingLevel={2} for a card used directly under a page's h1 with no intervening section:

Root element

The root renders as a <section>, labelled by title via aria-labelledby, whenever a title is given — an HTML5 <section> should have an accessible heading, and title is exactly that. With no title (a bare surface, or a header made up of just icon/action), the root stays a plain <div>, since an unlabelled <section> isn't a meaningful landmark.

Interactive (clickable) cards

Pass onSelect to turn the body into a real <button> — hover/focus affordance plus a centered, stacked content layout — for tile/action-card patterns like a component picker grid:

This is the same job MUI's CardActionArea does, folded into Card itself rather than a separate component — children must stay to phrasing content (text, spans, icons), since a native <button> can't contain block-level elements like <div>. onSelect is deliberately distinct from onClick: onClick is the plain pass-through to the root element (e.g. to stop click propagation on a whole panel), while onSelect specifically drives the interactive-body behavior described here.

Overriding surface styling

background/border/border-radius read from --card-background/--card-border/--card-radius custom properties (falling back to the design tokens above). A consumer embedding a Card for a different context — a docked panel with no elevation, a modal with a larger radius — can set these on its own wrapping class instead of fighting CSS-module specificity:

1.my-docked-panel {
2 --card-border: none;
3 --card-radius: 0;
4}

Props

PropTypeDefaultDescription
paddingnone | sm | md | lgnoneInternal padding — applies to the body when a header is present
iconReactNode—Optional icon rendered before the title
titleReactNode—Optional header title
headingLevel1 | 2 | 3 | 4 | 5 | 63Which heading tag wraps title
actionReactNode—Optional content rendered at the end of the header
onSelectMouseEventHandler<HTMLButtonElement>—Makes the body a clickable <button> with hover/focus affordance and a centered stack layout
scrollableBodybooleanfalseKeeps the header fixed and scrolls only the body; for cards with a bounded height
childrenReactNode—Card content
classNamestring—Additional class names

Compositions

Open all 8 →

Properties

Card props

PropTypeDefaultDescription
actionReactNode—Optional content rendered at the end of the header (buttons, menus, a close control, etc.)
childrenReactNode—Card body content
classNamestring—Additional class names to merge with the component root element
headingLevel5 | 1 | 2 | 3 | 4 | 63Which heading tag (`h1`–`h6`) wraps `title`, so the card's title takes its correct place in the page's heading outline. Defaults to `3`, matching a card nested one level below a page's `h1` title and a `section`'s `h2` — override per-instance when a card sits at a different depth.
iconReactNode—Optional icon rendered before the title in the header
onSelectMouseEventHandler<HTMLButtonElement>—Makes the body a real `<button>` — hover/focus affordance plus a centered, stacked content layout — for tile/action-card patterns (a picker grid, for example) instead of a static surface. Distinct from `onClick` (a plain pass-through to the root element, e.g. for stopping click propagation). Omit for a plain, non-interactive card.
padding"sm" | "md" | "lg" | "none"noneControls internal padding; defaults to none so consumers opt in. Applies to the body when a header is present.
scrollableBodybooleanfalseKeeps the header fixed and scrolls only the body when content exceeds the card's height. Only meaningful when the card has a bounded height (a modal or drawer panel, for example).
titleReactNode—Optional header title; omit along with `icon`/`action` to render no header

Also accepts the native attributes of its root element (className, aria-*, event handlers, …).