Components
Table
Table is used to display structured information in a neat and organized manner. Tables can make it easier for users to scan and compare information.
HTML
Unable to parse html
const Preview = () => { return ( <Table> <caption>Table caption</caption> <Table.Head> <Table.Row> <Table.HeaderCell>Header 1</Table.HeaderCell> <Table.HeaderCell>Header 2</Table.HeaderCell> <Table.HeaderCell>Header 3</Table.HeaderCell> </Table.Row> </Table.Head> <Table.Body> <Table.Row> <Table.Cell>Cell 1</Table.Cell> <Table.Cell>Cell 2</Table.Cell> <Table.Cell>Cell 3</Table.Cell> </Table.Row> <Table.Row> <Table.Cell>Cell 4</Table.Cell> <Table.Cell>Cell 5</Table.Cell> <Table.Cell>Cell 6</Table.Cell> </Table.Row> </Table.Body> <Table.Foot> <Table.Row> <Table.HeaderCell>Footer 1</Table.HeaderCell> <Table.HeaderCell>Footer 2</Table.HeaderCell> <Table.HeaderCell>Footer 3</Table.HeaderCell> </Table.Row> </Table.Foot> </Table> ); }; render(<Preview />)
Use table when
- the goal is to help users compare information easily
- the data needs a clear structure with rows and columns
- the content can benefit from sorting
Avoid using table when
- the purpose is to create layout or visually organise content on a page
- the information is better suited to a list or card view
- the content is very limited, for example only one column or very few data points without a need for comparison
- the table becomes difficult to read on mobile because the data set is large
Example
Zebra stripes
Zebra striping makes tables easier to read by visually separating rows. It helps users stay on the correct line.
HTML
Unable to parse html
const ZebraEn = () => { return ( <Table zebra> <caption>Number of applications per month</caption> <Table.Head> <Table.Row> <Table.HeaderCell>Month</Table.HeaderCell> <Table.HeaderCell>2023</Table.HeaderCell> <Table.HeaderCell>2024</Table.HeaderCell> </Table.Row> </Table.Head> <Table.Body> <Table.Row> <Table.HeaderCell scope='row'>January</Table.HeaderCell> <Table.Cell>1 230</Table.Cell> <Table.Cell>1 450</Table.Cell> </Table.Row> <Table.Row> <Table.HeaderCell scope='row'>February</Table.HeaderCell> <Table.Cell>980</Table.Cell> <Table.Cell>1 120</Table.Cell> </Table.Row> <Table.Row> <Table.HeaderCell scope='row'>March</Table.HeaderCell> <Table.Cell>1 150</Table.Cell> <Table.Cell>1 300</Table.Cell> </Table.Row> </Table.Body> </Table> ); }; render(<ZebraEn />)
With border
A border around the table can help users distinguish it from other content on the page.
HTML
Unable to parse html
const Border = () => { return ( <Table border> <Table.Head> <Table.Row> <Table.HeaderCell>Header 1</Table.HeaderCell> <Table.HeaderCell>Header 2</Table.HeaderCell> </Table.Row> </Table.Head> <Table.Body> <Table.Row> <Table.Cell>Cell 1</Table.Cell> <Table.Cell>Cell 2</Table.Cell> </Table.Row> </Table.Body> </Table> ); }; render(<Border />)
Numbers in a table
When numbers appear in a table and are meant to be compared, align them to the right within the cell.
HTML
Unable to parse html
const NumbersEn = () => ( <Table style={{ tableLayout: 'fixed', fontVariantNumeric: 'tabular-nums', }} > <caption>Number of applications per month</caption> <Table.Head> <Table.Row> <Table.HeaderCell scope='col'>Month</Table.HeaderCell> <Table.HeaderCell scope='col' style={{ textAlign: 'right' }}> 2023 </Table.HeaderCell> <Table.HeaderCell scope='col' style={{ textAlign: 'right' }}> 2024 </Table.HeaderCell> </Table.Row> </Table.Head> <Table.Body> <Table.Row> <Table.HeaderCell scope='row'>January</Table.HeaderCell> <Table.Cell style={{ textAlign: 'right' }}>1 230</Table.Cell> <Table.Cell style={{ textAlign: 'right' }}>1 450</Table.Cell> </Table.Row> <Table.Row> <Table.HeaderCell scope='row'>February</Table.HeaderCell> <Table.Cell style={{ textAlign: 'right' }}>980</Table.Cell> <Table.Cell style={{ textAlign: 'right' }}>1 120</Table.Cell> </Table.Row> <Table.Row> <Table.HeaderCell scope='row'>March</Table.HeaderCell> <Table.Cell style={{ textAlign: 'right' }}>1 150</Table.Cell> <Table.Cell style={{ textAlign: 'right' }}>1 300</Table.Cell> </Table.Row> </Table.Body> </Table> ); render(<NumbersEn />)
Sorting
You can show that the table supports sorting based on the content of a column.
HTML
Unable to parse html
const SortableEn = () => { const dummyData = [ { id: 1, name: 'Lise Example', email: 'lise@example.com', phone: '22345678', }, { id: 2, name: 'Kari Example', email: 'kari@example.com', phone: '87654321', }, { id: 3, name: 'Ola Example', email: 'ola@example.com', phone: '32345678', }, { id: 4, name: 'Per Example', email: 'per@example.com', phone: '12345678', }, ]; const [sortField, setSortField] = useState< keyof (typeof dummyData)[0] | null >(null); const [sortDirection, setSortDirection] = useState<TableHeaderCellProps['sort']>(undefined); const handleSort = (field: keyof (typeof dummyData)[0]) => { if (sortField === field && sortDirection === 'descending') { setSortField(null); setSortDirection(undefined); } else { setSortField(field); setSortDirection( sortField === field && sortDirection === 'ascending' ? 'descending' : 'ascending', ); } }; const sortedData = [...dummyData].sort((a, b) => { if (sortField === null) return 0; if (a[sortField] < b[sortField]) return sortDirection === 'ascending' ? -1 : 1; if (a[sortField] > b[sortField]) return sortDirection === 'ascending' ? 1 : -1; return 0; }); return ( <Table> <Table.Head> <Table.Row> <Table.HeaderCell sort={sortField === 'name' ? sortDirection : 'none'} onClick={() => handleSort('name')} > Name </Table.HeaderCell> <Table.HeaderCell>Email</Table.HeaderCell> <Table.HeaderCell sort={sortField === 'phone' ? sortDirection : 'none'} onClick={() => handleSort('phone')} > Phone </Table.HeaderCell> </Table.Row> </Table.Head> <Table.Body> {sortedData.map((row) => ( <Table.Row key={row.id}> <Table.Cell>{row.name}</Table.Cell> <Table.Cell>{row.email}</Table.Cell> <Table.Cell>{row.phone}</Table.Cell> </Table.Row> ))} </Table.Body> </Table> ); }; render(<SortableEn />)
Guidelines
Use table to structure and present data clearly in rows and columns.
- Content in tables should be left-aligned, except for numbers, which should be right-aligned to make comparison easier.
- Use
<Table.HeaderCell>for header cells, not<Table.Cell>. A cell counts as a header when it describes the content of the same row or column. - In table rows with several actions, you can use a menu to save space if the actions do not need to be visible at all times.
Text
Avoid long texts in table cells. Keep content short and concise so it is easy to scan across rows and columns. If you need to show more information, consider linking to a detail page. Use headers to tell users what type of content they will find in the rows and columns.
As a general rule, content in cells should be left-aligned to make it easier to read and scan. The exception is numbers and currency and sometimes form elements and buttons.
Edit this page on github.com (opens in a new tab)