Skip to content

Data tables

Density, alignment, sorting, filtering, selection and bulk actions — tables that stay readable at a hundred rows.

Tables are for comparing. Every decision below serves one goal: let people scan a column, compare rows and act on them without losing their place.

InvoiceStatus
INV-2043InitechOverdueAug 30$890.00
INV-2046Wayne EnterprisesOverdueSep 1$1,999.00
INV-2041Northwind TradersPaidSep 2$12,400.00
INV-2044Umbrella HealthPaidSep 10$25,600.00
INV-2042GlobexPendingSep 28$3,180.50
INV-2045Stark IndustriesPendingOct 4$7,420.75

6 of 6 invoices

Alignment

  • Text left, numbers right. Right-aligned numbers with tabular figures line up digit by digit. prfct tables use tabular figures by default.
  • Headers align with their content.
  • Units in the header, not repeated in every cell, when a column shares one.

Density

Rows are 48px by default — comfortable for mixed content. For dense operational tables, use 40px rows with sm controls; don't go below 32px. Keep one density per table.

Sorting and filtering

  • Make sortable headers buttons, with an icon that shows the direction, and set aria-sort on the header cell.
  • Put search and filters above the table, and show the result count below it.
  • When filters exclude everything, keep the headers and show an empty state inside the table with a way to clear filters.

Selection and bulk actions

  • A checkbox column with a header checkbox that is indeterminate when some — but not all — rows are selected.
  • When rows are selected, a bulk action bar replaces the toolbar, states the count and offers the actions. Destructive bulk actions follow Destructive actions.
  • Selected rows use data-state="selected", tinted with brand-2.

Pagination

Use pagination when position matters — people need to find the invoice from last March again. Use infinite scroll only for feeds that are browsed, not searched. Always show the total.

Accessibility

  • Use real table markup: thead, th with scope, and a caption (visually hidden if needed).
  • Every row checkbox has a label that names the row: Select INV-2043.
  • Row actions are reachable with the keyboard; avoid actions that only appear on hover.