Skip to main content
On this page

Display structured data in rows and columns for comparison and review.

When to use​

  • To display structured data where rows and columns have a meaningful relationship
  • When users need to compare values across multiple items of the same type
  • When the data has a consistent structure, with the same attributes for every row

When not to use​

  • For layouts - use Stack or Cluster instead. Tables impose structure that assistive technologies use for navigation, and misusing them creates an inaccessible experience.
  • For key-value pairs describing a single entity - use Summary List instead, for example a customer's name, address, and account number.
  • For a single list of values - use a List instead.
  • For data without a clear row-column relationship - if cells do not gain meaning from their position in both a row and a column, the data is not tabular.

Anatomy​

  1. Caption
  2. Column header
  3. Row header
  4. Cell

Basic usage​

The simplest way to use DataTable is with the items and columnHeadings props.

Loading...
Edit live code
<DataTable
  columnHeadings={['Day', 'Average', 'Max', 'Min']}
  items={[
    ['Today', '222', '260', '147'],
    ['Tomorrow', '254', '279', '211'],
    ['Wednesday', '174', '223', '135']
  ]}
  caption={<Strong>National Grid Carbon Intensity Forecast (gCO2/kWh)</Strong>}
/>

Variants and features​

Row headers​

Use rowHeadings when the first column identifies the row rather than containing a data value, for example a meter serial number or account ID. This renders the first cell of each row as a <th scope="row"> so that screen readers can announce the row identity before each cell value.

Loading...
Edit live code
<DataTable
  columnHeadings={['Day', 'Average', 'Max', 'Min']}
  items={[
    ['Today', '222', '260', '147'],
    ['Tomorrow', '254', '279', '211'],
    ['Wednesday', '174', '223', '135'],
  ]}
  caption={<Strong>National Grid Carbon Intensity Forecast (gCO2/kWh)</Strong>}
  rowHeadings={true}
/>

Striped rows​

Row striping alternates the background colour of odd rows and is on by default. It helps users track across wide tables. Only disable striping for compact tables where alternating backgrounds add visual noise without helping readability.

Striping on, the default:

Loading...
Edit live code
<DataTable
  columnHeadings={['Day', 'Average', 'Max', 'Min']}
  items={[
    ['Today', '222', '260', '147'],
    ['Tomorrow', '254', '279', '211'],
    ['Wednesday', '174', '223', '135'],
  ]}
  caption={<Strong>Striped (default)</Strong>}
  rowHeadings={true}
/>

Striping off, with striped={false}:

Loading...
Edit live code
<DataTable
  columnHeadings={['Day', 'Average', 'Max', 'Min']}
  items={[
    ['Today', '222', '260', '147'],
    ['Tomorrow', '254', '279', '211'],
    ['Wednesday', '174', '223', '135'],
  ]}
  caption={<Strong>Not striped</Strong>}
  rowHeadings={true}
  striped={false}
/>

Fixed column widths​

Use columnWidths to prevent columns from resizing as content changes. Pass a CSS width value for each column position. Columns without a fixed width will share the remaining space.

Loading...
Edit live code
<DataTable
  columnHeadings={['Day', 'Average', 'Max', 'Min']}
  items={[
    ['Today', '222', '260', '147'],
    ['Tomorrow', '254', '279', '211'],
    ['Wednesday', '174', '223', '135'],
  ]}
  caption={<Strong>National Grid Carbon Intensity Forecast (gCO2/kWh)</Strong>}
  rowHeadings={true}
  columnWidths={['12rem', '6rem', '6rem', '6rem']}
/>

Composable usage​

For tables that need custom rendering, for example mixed cell types or specific row grouping that the items prop cannot express, use the exported sub-components directly as children.

The sub-components are: TableHead, TableBody, TableRow, TableHeader, TableRowHeader, TableCell, and TableCaption. Each accepts a cellWidth prop in addition to its native HTML element attributes.

When composing, the striped prop does not apply. Set stripe on each alternating TableRow yourself.

Loading...
Edit live code
<DataTable>
  <TableCaption>
    <Strong>Meter reads awaiting validation</Strong>
  </TableCaption>
  <TableHead>
    <TableRow>
      <TableHeader scope="col">Meter serial</TableHeader>
      <TableHeader scope="col">Reading</TableHeader>
      <TableHeader scope="col">Status</TableHeader>
    </TableRow>
  </TableHead>
  <TableBody>
    <TableRow>
      <TableRowHeader scope="row">A1234567</TableRowHeader>
      <TableCell>12,044</TableCell>
      <TableCell><Badge variant="success">Accepted</Badge></TableCell>
    </TableRow>
    <TableRow stripe>
      <TableRowHeader scope="row">B7654321</TableRowHeader>
      <TableCell>8,910</TableCell>
      <TableCell><Badge variant="warning">Pending</Badge></TableCell>
    </TableRow>
  </TableBody>
</DataTable>