Skip to content

Table ​

Rows of data with column headings, which people can sort: applicants, classes, invoices.

Open in Storybook to try every prop.

When to use ​

Use a Table forUse instead
Many records with the same fields, to compare or scanOne record's details (SummaryList)
Data people sort or look across by columnA few items with mixed content (a list in a Card)
Totals under a list of amountsA single headline number (StatTile)

Anatomy ​

PartRequiredNotes
scroll areaYesScrolls sideways when the columns don't fit; up and down too with a max height.
captionRecommendedNames the table. Hidden unless showCaption.
header rowYesColumn headings, black 65%, bold. Sortable ones are buttons with a sort icon.
rowsYesOne per record, with a line between.
row headerNoOne column (usually the first, e.g. a name) can head its row. Bold.
footerNoRows in a <tfoot>, e.g. totals. Bold, with a line above.
empty / loadingNoOne centred row when there are no rows.

No border or background of its own: put it in a Card with padding="none".

Properties ​

PropertyTypeDefaultDescription
columnsTableColumn[]—Required. See Columns.
rowsobject[]—Required.
rowKeystring | (row, index) => keyindexA unique field, so rows stay stable when sorted.
captionstring—The table's accessible name.
showCaptionbooleanfalseShow the caption above the table.
sort{ key, direction } | nullnullv-model:sort.
manualSortbooleanfalseOnly report the sort (e.g. to sort on the server); don't re-order rows.
sizemd | smmdSee Sizes.
stickyHeaderbooleanfalseKeep the headings in view. Give the table a max height.
loadingbooleanfalseNo rows: a spinner. With rows: rows dimmed to 50%.
emptyTextstring"Nothing to show."Slot empty for richer content.
ui—Extra classes per part.

Columns ​

FieldTypeDefaultDescription
keystring—Required. The field shown, and the slot name cell-{key}.
labelstring—Required. Heading text.
hideLabelbooleanfalseHeading read out but not shown, e.g. an actions column.
alignstart | endstartEnd for numbers and amounts, so digits line up (they also use tabular figures).
sortablebooleanfalseHeading becomes a sort button.
sortValue(row) => valuerow[key]What to sort by, e.g. a date's timestamp.
rowHeaderbooleanfalseCells are row headings (<th scope="row">). One column at most.
nowrapbooleantrueKeep cells on one line. Turn off for long text.
classstring—Extra classes for the column, e.g. a width.

Sizes ​

SizeCell paddingRow height (one line)
md16px sides, 12px top and bottom44px
sm16px sides, 8px top and bottom36px
PartValue
Text14px / 20px; headings bold, black 65%; the sorted heading black
Sort icon16px, 4px after the label; unsorted black 40%
Lines1px black 15%, under the header and between rows (not after the last)
Empty / loading row32px top and bottom, centred, black 65%

Sorting ​

ActionResult
Click a sortable headingAscending, then descending, then back to the original order
TextNatural order ("Year 2" before "Year 10"), ignoring case
Empty valuesLast, whichever direction
TiesKeep their original order

States ​

StateAppearance
Heading hoverText goes from black 65% to black
Heading focused2px focus ring #007FC9, 1px outside (keyboard only)
Scroll area focusedThe same ring, 2px inside the edge so a Card's corners don't clip it (only when it scrolls)
Loading, no rows16px spinner and "Loading…"
Loading, with rowsRows at 50% opacity

Accessibility ​

PartAnnounced as
Tabletable, named by its caption; aria-busy while loading
Sortable headingcolumnheader with aria-sort (none / ascending / descending), containing a button named by the label
Row header cellsrowheader, so each cell is read with its row's name
Scroll area (when it scrolls)region named by the caption, focusable so the keyboard can scroll it
Icon-only cells (e.g. a ⋯ menu)Name the button with the row, e.g. "More for Amelia Clarke"

Platform adaptation ​

PlatformImplementationDifferences
Web / desktop (Vue)Table.vue—
iOS (SwiftUI)—Table on iPad and Mac; a List of rows on iPhone.
Android (Compose)—A LazyColumn of rows; columns become label / value pairs on phones.

Tokens used ​

TokenUsed for
color blacktext, sorted heading
color black (65%)headings, empty text
color black (40%)unsorted icon
color black (15%)lines
color whitesticky header background
color focusfocus rings

Do / Don't ​

DoDon't
Give every table a captionRely on the surrounding heading alone
Right-align numbers and amountsCentre-align columns
Make the name column the row headerMake a whole row clickable with no link or button in it
Use slots for Badges, links and menusPut more than one or two actions in a row

Released under the PolyForm Noncommercial License 1.0.0.