Skip to content

Data table

Rows of records people scan, sort and select: hairline rows, small uppercase headers, and numbers right-aligned so they line up.

CSS
css/components/table.css
JS
js/components/table.js (optional)

01 — Variants

Sortable and selectable

Click a header to sort. data-select adds checkboxes and a select-all. On phones, .table--stack turns each row into label and value pairs.

Recent uploads
Title Posted Views Actions
Night bus1,204Edit
Dayton at dusk12.8kEdit
Studio, morning87Edit

Compact, no script

.table--compact has 32px rows. A plain table needs no script.

Control heights
TokenValuepx
--control-h2.5rem40
--control-h-touch2.75rem44
--control-h-lg3.5rem56

Empty

No rows? Put a compact empty state in one full-width cell.

Drafts
TitleEdited

No drafts

Posts you start and don’t publish are kept here.

02 — Behavior

Script

NameDetail
Sortingth[data-sort] sorts as text, number or date. A cell’s data-value or <time datetime> sorts in place of its text. Event: jewel:sort.
Selectiondata-select on the wrap. Selected rows get aria-selected="true". Event: jewel:selectionchange; API wrap.jewelTable.selected().
SizeWide tables scroll sideways inside .table-wrap. .table-wrap--tall fixes the height with a sticky header.
Rows as links.table__link on a row’s main link makes the whole row clickable.

03 — Usage

Use it for

  • Records people compare across several columns.
  • .is-num on number columns, so digits line up.

Avoid

  • Layout. Use the grid.
  • Two columns of facts. Use a meta list.
  • A chart’s data. Charts keep their own table view.

04 — Accessibility

Notes

  • A caption names the table. Headers use scope.
  • Sortable headers are buttons that announce the sort direction (aria-sort).

05 — Without Jewel’s JS

What the script does

A plain table needs no script. The script sorts rows, adds selection checkboxes and phone labels, and announces changes. The CSS reads only the markup below, so a framework can sort and select its own rows and leave out table.js and data-component.

StateSet thisNotes
Sortable header<button class="table__sort" type="button"> inside the th, holding its textSort the rows yourself.
Sortedaria-sort="ascending" or "descending" on that thShows the arrow. Remove it from the other headers.
Selection columnA first th.table__select and td.table__select, each holding <label class="choice"><input type="checkbox"> and a visually hidden name“Select all rows” in the header, “Select Night bus” in a row.
Selected rowaria-selected="true" on the tr, "false" otherwiseSelected fill. Set the select-all box’s indeterminate property when only some rows are selected.
Phone labelsdata-label="Posted" on each cell of a .table--stackThe column’s header text, shown beside the value on phones.
Scrollingtabindex="0", role="region" and aria-labelledby (the caption’s id) on .table-wrapOnly when it scrolls, so keyboard users can reach it.

Events and keyboard

  • The script announces “Sorted by Title, ascending” and “All rows selected” in a visually hidden polite live region.
  • jewel:sort and jewel:selectionchange don’t fire without the script.