v1.2.0
  1. ds
  2. Components
  3. Data table

Data table

Sort, select, filter and act on many rows.

owner: any
State Actions
load_orders data-platform Failing 96 4m 12s 4 min ago
customers_daily growth Healthy 1 30m 40s 6 h ago
events_to_lake data-platform Healthy 288 41s 1 min ago
refunds_sync payments Slow 24 15m 11s 38 min ago
inventory_snapshot supply Healthy 4 10m 10s 2 h ago
marketing_attribution growth Paused 0 – 9 days ago
fx_rates payments Healthy 24 12s 22 min ago
1–7 of 7
Show code
<div class="dtable">
  <div class="dt-bar">…search, filter chips, <button class="btn sm end">Columns</button></div>
  <div class="dt-bar bulk" hidden><b>3 selected</b> … <button class="btn sm ghost end">Clear selection</button></div>
  <div class="dt-scroll" style="--dt-h: 24rem">
    <table>
      <thead><tr>
        <th class="sel"><input type="checkbox" aria-label="Select all" /></th>
        <th aria-sort="ascending"><button>Pipeline</button></th>
        <th class="n"><button>p95</button></th>
        <th class="act"><span class="sr-only">Actions</span></th>
      </tr></thead>
      <tbody>
        <tr aria-selected="true">
          <td class="sel"><input type="checkbox" checked aria-label="Select load_orders" /></td>
          <td><b class="mono">load_orders</b></td>
          <td class="n">4m 12s</td>
          <td class="act"><button class="btn icon xs ghost" aria-label="Actions for load_orders">…</button></td>
        </tr>
      </tbody>
    </table>
  </div>
  <div class="dt-foot"><label>Rows per page <select class="inp sm">…</select></label><span>1–25 of 312</span><div class="btn-row">…</div></div>
</div>

The table with the parts a working list needs. The toolbar holds the search, active filters as chips and the column menu. Selecting rows swaps it for a bulk bar in the accent wash, so the actions appear where people are already looking. The head sticks while the body scrolls inside --dt-h.

Column heads that sort are buttons. The sorted column is in ink with an arrow; others show a faint pair of arrows on hover. Numbers are mono and right-aligned, and so are their heads. Row actions fade in on hover and are always visible on touch. Try sorting, filtering and selecting.

Compact, empty

QueryUserRowsTook
select * from fct_orders where …priya1,2040.8s
select count(*) from events_rawsameer114.2s
PipelineOwnerRuns
No pipelines match owner:finance. Clear filters
Show code
<div class="dtable compact">
  <table>
    <thead><tr><th>Query</th><th>User</th><th class="n">Rows</th><th class="n">Took</th></tr></thead>
    <tbody>
      <tr><td class="mono">select * from fct_orders where …</td><td>priya</td><td class="n">1,204</td><td class="n">0.8s</td></tr>
      <tr><td class="mono">select count(*) from events_raw</td><td>sameer</td><td class="n">1</td><td class="n">14.2s</td></tr>
    </tbody>
  </table>
</div>
<div class="dtable" style="margin-top:1rem">
  <table>
    <thead><tr><th>Pipeline</th><th>Owner</th><th class="n">Runs</th></tr></thead>
    <tbody><tr class="dt-empty"><td colspan="3">No pipelines match <b class="mono">owner:finance</b>. <a href="#">Clear filters</a></td></tr></tbody>
  </table>
</div>

API

ClassOnWhat it does
.dtabledivThe frame. A real <table> inside, optionally in .dt-scroll.
.dt-bardivToolbar. .end on a child pushes it right. .bulk for the selection bar.
.dt-scrolldivScrolls the table; the head sticks. --dt-h caps the height.
th > buttonthA sortable head. Put aria-sort on the th.
.nth, tdNumeric: right-aligned, mono in cells.
.selth, tdThe checkbox column.
aria-selected="true"trA selected row, washed in the accent.
.acttdRow actions, faded until hover.
.dt-footdivRows per page, the range, page buttons.
.dt-emptytrThe row shown when nothing matches.
.compact.dtableTighter rows.
Do
  • Say the range and the total: 1–25 of 312.
  • Keep selection when the sort changes, clear it when the filter does.
  • Units in the head when every row shares them.
Don't
  • Centred numbers.
  • Zebra stripes. Hairlines are enough, and hover shows the row.
  • Hiding the column that people filter by.

Accessibility

  • aria-sort goes on the th, not the button, and only on the sorted column.
  • The select-all checkbox becomes indeterminate when some rows are selected; announce the count in the bulk bar, which is a live region.
  • Every row checkbox and action button is labelled with the row's name.