TableCard
Card primitive for row-as-card layouts, used by DataTable's card and mobile views.
Quick Preview
Ada Okafor
ada.okafor@example.com
- Budget
- Location
- Assigned to
Nnamdi Kalu
nnamdi.kalu@example.com
- Budget
- Location
- Assigned to
Composition
TableCard renders a full card from convenience props (title, subtitle, badge, details, selection, actions, action). For full control, pass children and compose the sub-parts yourself:
TableCard
├── TableCardAction (optional full-card click/link overlay)
├── TableCardHeader
│ ├── TableCardSelection (checkbox / radio, stays interactive)
│ ├── TableCardTitle
│ ├── TableCardSubtitle
│ └── TableCardActions (menu / buttons, stay interactive)
└── TableCardDetails
└── TableCardDetail (label / value pairs)Usage
Convenience props cover the common case:
import { TableCard, TableCardAction } from "@giddaa-housing/ui/table-card";
import { Badge } from "@giddaa-housing/ui/badge";
<TableCard
title="Ada Okafor"
subtitle="ada.okafor@example.com"
badge={<Badge variant="success">Approved</Badge>}
details={[
{ label: "Budget", value: "₦85m" },
{ label: "Location", value: "Lekki, Lagos" },
]}
/>;Making the whole card clickable
TableCardAction renders an absolutely-positioned overlay so the entire card becomes a single link or button, while selection and actions stay clickable above it. Use render to swap the underlying element (e.g. a router link):
<TableCard
action={<TableCardAction render={<a href={`/buyers/${buyer.id}`} />} />}
selection={<Checkbox checked={selected} onCheckedChange={onSelect} size="sm" />}
actions={<BuyerRowMenu buyer={buyer} />}
title={buyer.name}
subtitle={buyer.email}
details={details}
/>Custom layouts
Pass children to bypass the default composition entirely:
<TableCard size="lg">
<TableCardHeader>
<TableCardTitle>Custom layout</TableCardTitle>
<TableCardActions>{/* menu */}</TableCardActions>
</TableCardHeader>
{/* anything you need */}
</TableCard>Use with DataTable
DataTableCardGrid renders a TableCard per row for card and mobile views. Prefer renderCard so table columns don't have to match the card layout:
<DataTableCardGrid
renderCard={(row, { action, selection }) => (
<TableCard
action={action}
selection={selection}
title={row.original.name}
subtitle={row.original.email}
details={[
{ label: "Budget", value: row.original.budget },
{ label: "Location", value: row.original.location },
]}
/>
)}
/>See DataTable for the full table experience.
Examples
Default card
Ada Okafor
ada.okafor@example.com
- Budget
- Location
- Assigned to
Nnamdi Kalu
nnamdi.kalu@example.com
- Budget
- Location
- Assigned to
Props
TableCard
| Prop | Type | Default | Description |
|---|---|---|---|
title | ReactNode | - | Primary heading (rendered as TableCardTitle). |
subtitle | ReactNode | - | Secondary line under the title. |
badge | ReactNode | - | Status badge shown below the header. |
details | TableCardDetailItem[] | - | Label/value rows; items with empty value are skipped. |
selection | ReactNode | - | Selection control (checkbox/radio) kept clickable above the card overlay. |
actions | ReactNode | - | Top-right actions (menu/buttons) kept clickable above the card overlay. |
action | ReactNode | - | Full-card overlay, typically a TableCardAction link/button. |
selected | boolean | false | Applies the selected (brand) styling and data-state="selected". |
size | "sm" | "md" | "lg" | "md" | Padding, gap, and radius scale. |
children | ReactNode | - | Replaces the default composition entirely. |
| native props | article props | - | Passed through to the root <article>. |
TableCardDetailItem
| Field | Type | Description |
|---|---|---|
label | ReactNode | Detail label. |
value | ReactNode | Detail value; renders nothing when null, undefined, or "". |
className / labelClassName / valueClassName | string | Per-row style overrides. |
Accessibility
- When using
TableCardActionas a link, give it an accessible name viaaria-labelor the overlaid text. - Keep
selectionandactionscontrols labelled; they intentionally receive clicks before the full-card overlay. - Don't rely on the
selectedbackground alone — pair it with a visible checkbox or text.