Components

Table

Table is a set of styled HTML table primitives for displaying simple tabular data.

Table provides styled HTML table elements as React components. It is intentionally minimal — it has no built-in sorting, filtering, or pagination. For those features use DataTable instead.

Use Table only when your data is truly static and needs no interaction. For anything dynamic, DataTable is the right choice.

() => (
<TableWrapper>
<TableRoot>
<TableCaption>Nutritional Information</TableCaption>
<TableHeader>
<TableRow>
<TableHeaderCell scope="col">Food Item</TableHeaderCell>
<TableHeaderCell scope="col">Calories</TableHeaderCell>
<TableHeaderCell scope="col">Total Fat</TableHeaderCell>
<TableHeaderCell scope="col">Protein</TableHeaderCell>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>🍔 Bacon Smokehouse Burger</TableCell>
<TableCell>840</TableCell>
<TableCell>45g</TableCell>
<TableCell>46g</TableCell>
</TableRow>
<TableRow>
<TableCell>🍔 Big Mac</TableCell>
<TableCell>540</TableCell>
<TableCell>28g</TableCell>
<TableCell>25g</TableCell>
</TableRow>
<TableRow>
<TableCell>🥗 Side Salad</TableCell>
<TableCell>20</TableCell>
<TableCell>0g</TableCell>
<TableCell>1g</TableCell>
</TableRow>
</TableBody>
</TableRoot>
</TableWrapper>
)

Components

Table exports a set of primitives that map directly to HTML table elements. Compose them together to build a table.

ComponentHTML elementPurpose
TableWrapperdivScroll container; provides accessible role="region" wrapper
TableRoottableThe table element
TableCaptioncaptionAccessible label; use displayCaption={false} to hide visually
TableHeadertheadHeader section
TableBodytbodyBody section
TableRowtrA row
TableHeaderCellthA header cell
TableCelltdA data cell

TableWrapper

TableWrapper wraps the table in a scrollable div with overflow-x: auto and wires up the accessible aria-labelledby relationship between the container and the caption automatically. Always use it as the outermost wrapper.

Custom Cell Content

Because cells accept React.ReactNode, you can render any content — links, badges, icons — directly inside TableCell or TableHeaderCell.

() => (
<TableWrapper>
<TableRoot>
<TableCaption>Team Status</TableCaption>
<TableHeader>
<TableRow>
<TableHeaderCell scope="col">Name</TableHeaderCell>
<TableHeaderCell scope="col">Role</TableHeaderCell>
<TableHeaderCell scope="col">Status</TableHeaderCell>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>Alice</TableCell>
<TableCell>Engineer</TableCell>
<TableCell><Badge badgeColor="green">Active</Badge></TableCell>
</TableRow>
<TableRow>
<TableCell>Bob</TableCell>
<TableCell>Designer</TableCell>
<TableCell><Badge badgeColor="green">Active</Badge></TableCell>
</TableRow>
<TableRow>
<TableCell>Charlie</TableCell>
<TableCell>Manager</TableCell>
<TableCell><Badge badgeColor="red">Inactive</Badge></TableCell>
</TableRow>
</TableBody>
</TableRoot>
</TableWrapper>
)

Row Headers

Use TableHeaderCell with scope="row" inside TableBody rows to mark a cell as the row's header. This improves screen reader navigation for tables where the first column identifies each row.

() => (
<TableWrapper>
<TableRoot>
<TableCaption>Q1 Targets</TableCaption>
<TableHeader>
<TableRow>
<TableHeaderCell scope="col">Team</TableHeaderCell>
<TableHeaderCell scope="col">Target</TableHeaderCell>
<TableHeaderCell scope="col">Actual</TableHeaderCell>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableHeaderCell scope="row">Engineering</TableHeaderCell>
<TableCell>12 features</TableCell>
<TableCell>14 features</TableCell>
</TableRow>
<TableRow>
<TableHeaderCell scope="row">Design</TableHeaderCell>
<TableCell>8 designs</TableCell>
<TableCell>7 designs</TableCell>
</TableRow>
<TableRow>
<TableHeaderCell scope="row">Marketing</TableHeaderCell>
<TableCell>4 campaigns</TableCell>
<TableCell>4 campaigns</TableCell>
</TableRow>
</TableBody>
</TableRoot>
</TableWrapper>
)

Accessibility

  • Always provide a TableCaption. Use displayCaption={false} only when the table's purpose is already clear from surrounding page context.
  • Use scope="col" on all TableHeaderCell elements in TableHeader.
  • Use scope="row" on TableHeaderCell elements in TableBody rows that identify each row.
  • TableWrapper automatically wires aria-labelledby between the container and caption for scrollable table regions.

Best Practices

  • Prefer DataTable for any table with dynamic data, sorting, filtering, or pagination.
  • Use Table only for simple, static tabular data where no interaction is needed.
  • Always wrap the table in TableWrapper to handle overflow and accessibility correctly.