Table
Responsive semantic table primitives for structured data and rich states
pnpm add @wandercom/design-system-web
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.
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>
);
}Table cells accept any content, including image-and-label pairs, badges, and two-line values.
Use TableState inside TableBody to preserve the header while centering an
empty, loading, or permissions state across the table columns.
Override contentClassName when a state needs additional vertical room for
actions or a longer message.
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:
<TableContainer>
<Table className="min-w-[720px]">{/* columns and rows */}</Table>
</TableContainer>