Brik Design System
Components

Table

Data table with composable subcomponents. Sorting, selection, striped rows, size variants.

Table is a composable data-display primitive. The container plus six subcomponents (TableHeader, TableBody, TableRow, TableHead, TableCell) handle the structural HTML; the consumer composes cells with whatever content the row needs — text, badges, links, action buttons.

Use it for

  • Tabular records with consistent columns (users, projects, invoices)
  • Sortable lists where the user picks a column to order by
  • Comparison tables on settings or pricing pages
  • Any "rows of structured data" where columns share semantics across rows

For card-like rows where each entry is its own self-contained block, use CardList. For settings panels with action-per-row, use CardControl.

Import

import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from '@brikdesigns/bds';

Variants

Sizes

<Table size="default">...</Table>      {/* compact, dense data */}
<Table size="comfortable">...</Table>  {/* generous padding, 72px cell height */}

Striped

Alternating row backgrounds for readability on dense tables.

<Table striped>...</Table>

Flush

flush removes the left padding on the first cell and right padding on the last — use when the table aligns to a container's edge with no internal padding.

<Table flush>...</Table>

Sortable headers

TableHead accepts sortable and sortDirection. The consumer owns the click handler and sort state.

<TableHead sortable sortDirection="asc" onClick={() => sortBy('name')}>
  Name
</TableHead>

Selected rows

TableRow accepts a selected boolean for highlight styling.

<TableRow selected>
  <TableCell>Active row</TableCell>
</TableRow>

Cell pattern standards

These patterns recur often enough to standardize. Don't reach for raw <a> or <button> inside a TableCell — use the BDS components below.

Action buttons

Use size="sm" for all buttons inside cells.

{/* Text button */}
<Button variant="primary" size="sm">View</Button>

{/* Icon buttons — always IconButton, never raw <button> */}
<IconButton variant="primary" size="sm" icon={<EditIcon />} label="Edit" />
<IconButton variant="danger" size="sm" icon={<TrashIcon />} label="Delete" />

Common icon-button variants for table actions:

VariantUse
primaryPrimary action (edit, open)
secondaryNeutral (download, copy)
ghostLow emphasis (overflow menu)
dangerDestructive (delete, remove)

Use <TextLink size="small"> for in-cell navigation. Never use raw <a> or full-size text links.

<TextLink href="/profile/123" size="small">View profile</TextLink>

<TextLink href="#" size="small" iconAfter={<ExternalLinkIcon />}>
  Open
</TextLink>

Text link vs button:

  • TextLink — navigation that takes you somewhere (View profile, Open document)
  • Button — actions that change state (Approve, Assign, Archive)

Tooltip indicators

Wrap info icons in a Tooltip so they reveal context on hover/focus. Use cursor: help to signal interactivity.

<Tooltip content="Primary contact email" placement="top">
  <span style={{ cursor: 'help' }}>
    <Icon icon="ph:info" />
  </span>
</Tooltip>

Icon-left cells

Pair a 24px icon with text using gap: var(--gap-xs).

<span style={{ display: 'flex', alignItems: 'center', gap: 'var(--gap-xs)' }}>
  <Icon icon="ph:palette" />
  Design
</span>

When not to use

  • Don't use Table for self-contained card grids. Cards belong in CardList.
  • Don't use Table for settings rows. Use CardControl — locked layout for badge + title + description + action.
  • Don't use Table for narrow mobile views. Tables don't gracefully wrap; consider a card-list layout for mobile-first data.

Accessibility

  • Renders real <table> / <thead> / <tbody> / <tr> / <th> / <td> — semantics are platform-native.
  • Sortable headers carry aria-sort reflecting the current sort direction.
  • Selected rows use aria-selected.
  • Action buttons in cells are real buttons — keyboard, focus, screen reader announce normally.

API

Table

PropTypeDefault
stripedbooleanfalse
size'default' | 'comfortable''default'
flushbooleanfalse
childrenReactNode (required)

Plus standard <table> HTML attributes.

Subcomponents

ComponentElementNotable props
TableHeader<thead>
TableBody<tbody>
TableRow<tr>selected: boolean
TableHead<th>sortable: boolean, sortDirection: 'asc' | 'desc'
TableCell<td>

All subcomponents accept their respective HTML attributes.

Usage

import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from '@brikdesigns/bds';
import { Badge, Button, IconButton, TextLink } from '@brikdesigns/bds';

<Table striped size="comfortable">
  <TableHeader>
    <TableRow>
      <TableHead sortable sortDirection="asc">Name</TableHead>
      <TableHead>Email</TableHead>
      <TableHead>Status</TableHead>
      <TableHead>Profile</TableHead>
      <TableHead style={{ textAlign: 'right' }}>Actions</TableHead>
    </TableRow>
  </TableHeader>
  <TableBody>
    <TableRow>
      <TableCell>Alice Chen</TableCell>
      <TableCell>alice@example.com</TableCell>
      <TableCell><Badge status="positive" size="sm">Active</Badge></TableCell>
      <TableCell><TextLink href="#" size="small">View profile</TextLink></TableCell>
      <TableCell style={{ textAlign: 'right' }}>
        <IconButton variant="primary" size="sm" icon={<EditIcon />} label="Edit" />
        <IconButton variant="danger" size="sm" icon={<TrashIcon />} label="Delete" />
      </TableCell>
    </TableRow>
  </TableBody>
</Table>

On this page