Table

Table displays structured data in rows and columns so users can scan, compare, analyse, and act on information.

When to use

  • The user needs to compare multiple records across a consistent set of attributes.
  • The data has a clear row-and-column structure that helps users scan, find, and act on information.
  • The dataset is large enough to benefit from sorting, pagination, or sticky headers to preserve context.

When not to use

  • If the table contains many interactive elements and users need cell-by-cell keyboard navigation, use a data grid (a keyboard-navigable table with ARIA grid semantics) instead.
  • If the data has no natural column structure and comparison across rows is not the goal, use a List or Card layout instead.

Usage guidance

How to structure, align, decorate, and extend tables so users can scan, compare, and act on data.

Header positioning

Most tables have headers at the top row. In some cases it makes sense to place headers in the first column instead, or to use both when the data has two dimensions, such as a timetable with weekdays across and timeslots down.

Table with headers in both the top row (weekdays) and the first column (timeslots), forming a two-dimensional timetable.
Table with dual headers: weekdays across the top and timeslots down the first column. Use when data has two dimensions.

Column order and alignment

Prioritise columns by importance, typically from left to right. On narrow screens the rightmost columns will be the first hidden from view.

Closely related columns of unequal importance can stay together when the two columns are only meaningful read together and separating them would force users to cross-reference.

Apply these alignment rules for easier scanning:

  • Left-align text, including non-countable numerals such as dates and phone numbers.
  • Right-align numbers, and consider monospaced numbers.
  • Align each heading the same way as the data in its column.

Center alignment can be appropriate when the cell content is made of equal-width icons.

Table columns showing text left-aligned, numbers right-aligned, and headings aligned with their data.
Table alignment: left-align text, right-align numbers, and match heading alignment to data. This reduces noise and supports scanning.

Vertical alignment

Middle-align cell content when row heights vary by no more than two to three lines. Switch to top alignment when rows vary more, because middle alignment makes longer cells harder to scan. Avoid bottom alignment in most cases. It risks hiding content near the viewport edge, especially with multi-line cells of varying length.

Do
Table rows with middle-aligned cell content where row heights vary by no more than two to three lines.
Do: middle-align cell content when rows vary only slightly, up to two to three lines. Keeps rows feeling balanced.
Don't
Table rows with top-aligned content where variation is minimal, adding unnecessary vertical offset.
Don't: top alignment when rows barely differ. It pushes content toward the top edge unnecessarily.
Do
Table rows with top-aligned cell content where some cells contain significantly more text than others.
Do: top-align when row content varies more than two to three lines. It anchors the reading position and improves scannability.
Don't
Table rows with middle-aligned cell content where row heights vary dramatically, making longer cells hard to read.
Don't: middle alignment with significant variation. Longer cells float awkwardly and lose their reading anchor.
Don't
Table rows with bottom-aligned content where some cells are multi-line, pushing earlier content above the viewport edge.
Don't: bottom alignment risks hiding content near the viewport edge, especially with multi-line cells of varying length.

Handling overflow

When the table overflows horizontally, keep headers or the first column sticky so users do not lose track of what the data represents.

A table on a narrow viewport with a horizontal scrollbar, showing that some columns extend beyond the visible area.
Table overflow: horizontal scroll is the simplest approach for wide tables on narrow screens. Make sure a visible cue shows that more columns exist.
A table with its first column frozen in place while the remaining columns scroll horizontally beneath a shadow edge indicator.
Table overflow with sticky column: the first column stays visible to preserve context as the user scrolls through remaining columns.

Patterns

Common compositions that extend a table to handle structure, overflow, and large datasets.

Header groups

Use header groups to reduce duplicated labels and make the overall table structure easier to scan.

Table with a parent header row spanning two child columns beneath it, grouping related attributes under one label.
Table header groups: a parent header spanning related child columns reduces repetition and makes the overall structure clearer.

Header tooltips

Use header tooltips when a column label might be misunderstood or uses acronyms that need clarification (e.g. INCO terms).

Table header with a tooltip open, showing an expanded explanation for an abbreviated column label.
Table header tooltip: use when the label is necessarily brief (acronyms, INCO terms) and a tooltip can carry the clarification without cluttering the row.

Use a footer when numerical data needs summarising. Make the footer visually distinct from the body so users can tell it represents a summary, not another record.

Table with a footer row in a distinct style (bold text, separator line above) displaying column totals.
Table footer: a footer row visually distinct from the body, showing column totals.

Combining columns

Combine two columns into one cell only when they describe the same entity (for example port and country) and users read them together rather than comparing them independently. Keep them in separate columns when users need to sort or scan either value on its own.

Table with two related data points (e.g. port and country) merged into one column cell.
Do: combine two columns into one cell when they describe the same entity and users read them together.
Table with related attributes kept in separate columns to support side-by-side comparison.
Caution: keep values in separate columns when users need to sort or scan either one independently.

Combining saves horizontal space but removes the ability to sort or scan either value on its own, so weigh it against how users work with the data.

Colspan and rowspan

Use colspan when a label or description needs to span multiple columns, and rowspan when a label applies to multiple rows. Prefer header groups when the only goal is to group columns under one category.

Table row with a cell spanning three columns, containing a description that applies to the full row width.
Table colspan: a cell spanning multiple columns suits descriptions or notes that apply across the full row rather than a single attribute.
Table with a cell in the first column spanning three rows, grouping those rows under a single label.
Table rowspan: a label spanning multiple rows groups related records under one category without repeating it in each row.

Row decoration

Keep table decoration minimal. Use alignment and hierarchy first, then add only the separators needed for comprehension.

Horizontal row separators are the default and should be applied in most tables since they guide the eye along each row.

Do
Table with only horizontal row separators, no vertical lines, appearing clean and uncluttered.
Do: horizontal lines only. Clean and sufficient for most tables.

Vertical lines separate columns and help compare values across rows, but they are rarely needed when columns are well aligned. They are more common in large or advanced data grids.

Caution
Table with both horizontal and vertical gridlines, creating a dense spreadsheet-like appearance.
Caution: adding vertical lines creates a spreadsheet-like expression that may suit dense data grids but feels heavy for simpler tables.

Row highlight on hover lets users focus on one row at a time without adding permanent clutter. It has no benefit on touch devices.

Table showing one row highlighted with a subtle background tint while the pointer hovers over it.
Table row hover: highlighting helps sighted mouse users focus on one row at a time. No benefit on touch devices.

Zebra stripes (alternating row background colours) can improve scannability for tables with many columns that scroll horizontally, but they add visual clutter and may cause contrast issues. Consider horizontal lines or hover highlighting first.

Table with alternating row background colours (zebra striping) applied to a wide, multi-column layout.
Zebra stripes can help distinguish rows in very wide tables but should be weighed against the added visual noise.

Expandable rows

Use expandable rows for simple, structured supplementary information while keeping the parent row visible for context.

Table with one row expanded to reveal structured detail content beneath it, while the parent row remains visible.
Table expandable row: use when the supplementary information is simple, structured, and tightly tied to its parent row.
Table with one row expanded to show a grouped list of sub-items beneath it.
Expandable rows are also suitable for displaying simple, well-grouped lists that keep the interface manageable.

Use headings, bullet points, or small tables to keep expanded content structured. Limit expansion to one level. Further nesting overwhelms rather than informs. If the supplementary information is large or interactive, move it to a modal or side panel instead. Avoid expanding several rows at once when the expanded content would push the remaining rows out of view.

Sorting and filtering

Allow sorting through clickable headers and show the active sorting mode clearly with a visible icon or direction cue. The expected sort cycle is:

  1. Default / unsorted (↑↓)
  2. Ascending order (↑ 0–9, a–z)
  3. Descending order (↓ 9–0, z–a)
Table header row with sort indicators: an active ascending arrow on one column and neutral double-arrows on unsorted columns.
Table sorting: make both the availability of sorting (neutral indicator) and the active sort direction (directional arrow) unmistakable.

Filtering works alongside sorting to help users narrow large datasets before comparing rows. For guidance on filter placement, behaviour, and interaction with sorting and pagination, see the search, filter, and sort guidelines.

Pagination

Split large row sets across pages when a single view no longer supports overview or comparison.

Table with a pagination bar below it showing page numbers, navigation arrows, and a rows-per-page selector.
Table pagination: split large row sets across pages when a single view no longer supports overview or comparison.

Toolbar

The table supports two toolbar types: a default toolbar for table-wide actions and a bulk action toolbar for actions on selected rows. Only one toolbar is visible at a time. The bulk action toolbar takes priority when one or more rows are selected.

Default toolbar

Use the default toolbar when actions apply to the entire table or dataset, are frequently accessed but not destructive, and do not depend on row selection.

Table with a toolbar above it containing action buttons for export, filter, and configuration.
A default toolbar with table-wide actions such as export and configuration.

Bulk action toolbar

Use the bulk action toolbar when actions require row selection and the same action can be applied to multiple items.

Table with selected rows and a bulk action toolbar showing primary actions and an overflow menu for secondary actions.
Table bulk action toolbar: appears when rows are selected, replacing the default toolbar. Includes primary actions and an overflow menu for secondary ones.

Content guidance

  • Use a less-is-more approach to selecting and structuring the data so the table supports decision-making without overload.
  • Keep header labels as short as possible to increase clarity and avoid truncation or wrapping.
  • Declutter repetitive data by using conventional icons, abbreviations, and shared units in headers instead of repeating them in every cell.
  • Use a dash when a cell contains no data so users know the content was loaded and is intentionally absent.
  • Let long cell content wrap by default. Only truncate when hiding the full value will not block understanding and users can access the complete text through an alternative such as a tooltip. Read more in the truncation guidelines.
Do
Table cells using status icons and abbreviated units in the header instead of repeating full text in every cell.
Do: use conventional icons and shared units in headers to reduce per-cell repetition and improve scannability.
Don't
Table cells repeating the full unit and status text in every row, creating redundant visual noise.
Don't: repeat full labels, units, and status text in every cell, which clutters the view and slows scanning.
Do
Table cell displaying a dash (—) to indicate no value exists for that attribute.
Do: use a dash so users see the value is intentionally missing, not unloaded.
Don't
Table cell left completely empty with no indicator, creating ambiguity about whether data is absent or failed to load.
Don't: leave cells empty, since users can't tell if data is absent or failed to load.

States and feedback

Keep table headers visible when the table changes state so users still understand what data the view is meant to contain.

  • Empty state: use when the table has not been populated yet.
  • Loading state: show a loading state when data takes more than about one second to arrive. The more accurate the progress information, the better.
  • No results state: explain the reason and show a path back to relevant data.
  • Error and warning state: make failure visible and keep the user oriented in the table context.
Table showing column headers with an empty body area containing an illustration and message indicating no data exists yet.
Table empty state: use when the table exists but has no data yet.
Table showing column headers with skeleton placeholder rows indicating data is loading.
Table loading state: show when data takes more than about a second; the more accurate the progress, the better.
Table showing column headers with an empty body containing a message explaining why no results matched and a link to clear filters.
Table no-results state: explain why nothing matched and offer a path back to data.
Table showing column headers with the body replaced by an error notification explaining the failure.
Table error state: replace rows with a clear failure message instead of leaving users to infer what broke.

Accessibility

  • Include a header so assistive technologies and sighted users can understand what each column or row contains.
  • Use a simple table structure wherever possible.
  • Provide a caption or equivalent description so the table purpose is clear.
  • Avoid empty cells. Use a dash to indicate intentionally absent values (see Content guidance above).
  • Do not use tables for layout purposes.
  • When many interactive elements make keyboard or screen-reader navigation repetitive, use a data grid as described in When not to use above.

The component already renders semantic header cells, exposes sort state, applies sticky positioning, and associates the caption with the table. Read more in the accessibility guidelines.

ComponentUse case
PaginationWhen a table has too many rows for a single page and overview needs to be restored
TooltipWhen a column header needs a short clarification that would not fit in the label
NotificationWhen loading fails or a warning condition needs to be communicated clearly
ModalWhen inline row expansion would overload the table and a focused disclosure is needed

See also