TableCard

Card primitive for row-as-card layouts, used by DataTable's card and mobile views.

Quick Preview

Ada Okafor

ada.okafor@example.com

Approved
Budget
₦85m
Location
Lekki, Lagos
Assigned to
Zainab B.

Nnamdi Kalu

nnamdi.kalu@example.com

In review
Budget
₦64m
Location
Maitama, Abuja
Assigned to
Unassigned

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

Approved
Budget
₦85m
Location
Lekki, Lagos
Assigned to
Zainab B.

Nnamdi Kalu

nnamdi.kalu@example.com

In review
Budget
₦64m
Location
Maitama, Abuja
Assigned to
Unassigned

Props

TableCard

PropTypeDefaultDescription
titleReactNode-Primary heading (rendered as TableCardTitle).
subtitleReactNode-Secondary line under the title.
badgeReactNode-Status badge shown below the header.
detailsTableCardDetailItem[]-Label/value rows; items with empty value are skipped.
selectionReactNode-Selection control (checkbox/radio) kept clickable above the card overlay.
actionsReactNode-Top-right actions (menu/buttons) kept clickable above the card overlay.
actionReactNode-Full-card overlay, typically a TableCardAction link/button.
selectedbooleanfalseApplies the selected (brand) styling and data-state="selected".
size"sm" | "md" | "lg""md"Padding, gap, and radius scale.
childrenReactNode-Replaces the default composition entirely.
native propsarticle props-Passed through to the root <article>.

TableCardDetailItem

FieldTypeDescription
labelReactNodeDetail label.
valueReactNodeDetail value; renders nothing when null, undefined, or "".
className / labelClassName / valueClassNamestringPer-row style overrides.

Accessibility

  • When using TableCardAction as a link, give it an accessible name via aria-label or the overlaid text.
  • Keep selection and actions controls labelled; they intentionally receive clicks before the full-card overlay.
  • Don't rely on the selected background alone — pair it with a visible checkbox or text.

On this page