Table

Responsive semantic table primitives for structured data and rich states

Installation

pnpm add @wandercom/design-system-web

Usage

Compose the table primitives directly. TableContainer adds horizontal overflow on small screens while Table stays a plain semantic table that is easy to use with server rendering or a virtualized data layer.

34 lines
import {
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableHeader,
  TableRow,
} from '@wandercom/design-system-web/ui/table';

export function ReservationsTable({ reservations }) {
  return (
    <TableContainer>
      <Table className="min-w-[720px]">
        <TableHeader>
          <TableRow className="h-10">
            <TableHead>Property</TableHead>
            <TableHead>Customer</TableHead>
            <TableHead>Date</TableHead>
          </TableRow>
        </TableHeader>
        <TableBody>
          {reservations.map((reservation) => (
            <TableRow interactive key={reservation.id}>
              <TableCell>{reservation.property}</TableCell>
              <TableCell>{reservation.customer}</TableCell>
              <TableCell>{reservation.dates}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  );
}

Examples

Rich cells

Table cells accept any content, including image-and-label pairs, badges, and two-line values.

Loading example...

Empty state

Use TableState inside TableBody to preserve the header while centering an empty, loading, or permissions state across the table columns.

Loading example...

Error state

Override contentClassName when a state needs additional vertical room for actions or a longer message.

Loading example...

Responsiveness and Performance

Table ships without a data engine, state, effects, or client-only directive. For ordinary datasets, map rows directly as shown above. For very long datasets, use these primitives as the styled markup emitted by TanStack Table and a virtualizer such as react-virtuoso; TableContainer is intentionally separate so a virtualizer can own its scroll parent.

Keep a readable minimum table width and place it in TableContainer for horizontal touch scrolling on narrow layouts:

3 lines
<TableContainer>
  <Table className="min-w-[720px]">{/* columns and rows */}</Table>
</TableContainer>

API

Table Primitives

TableContainer

React.ComponentProps<"div">
Optional responsive horizontal scrolling viewport for the table.

Table

React.ComponentProps<"table">
Semantic, fixed-layout table root with collapsed borders.

TableHeader

React.ComponentProps<"thead"> & { sticky?: boolean }
Header group with table label typography. Set sticky to pin it within a scrolling ancestor.

TableBody / TableFooter

React.ComponentProps<"tbody" | "tfoot">
Semantic table row groups.

TableRow

React.ComponentProps<"tr"> & { interactive?: boolean }
72px divided row. Set interactive for hover and focus treatment on actionable rows.

TableHead / TableCell

React.ComponentProps<"th" | "td">
Header and body cells with designed typography and spacing.

TableCaption

React.ComponentProps<"caption">
Accessible table caption displayed beneath the table.

TableState

colSpan

number
Number of visible columns covered by the full-width state row.

contentClassName?

string
Additional classes for the centered content area, such as a taller error state.

children?

React.ReactNode
Loading, empty, error, or custom table state content.
Table