Skip to content

Table

Table — one anatomy in two sizes: a card on surface/card at radius/16 with elevation/card, an accent-dark header bar, row-header pills, 2 px dividers and no vertical lines; the Accent mode drives it (a neutral-800 bar and neutral-200 pills in multicolor — the grey SWOT).

Beta · Content blocks · packages/css/src/components/table.css · React on Base UI: @pepperui/table

.pui-table (--slide) · __table __row __cell (--header --row-header --right) · __pill __sort · row aria-selected. The last row has no divider.

Table — every size and every stateOpen in the workshop

Sizes across, states down.

  • Size slide (four columns, the first a pill column) / product (body 13 Regular, header 14 Medium, padding 12 × 16; six columns, no pills; what Data table composes)
  • Header row and Rows 1–5 are exposed — edit every cell; Has row 4 / Has row 5 drop to three rows; columns 5 and 6 are switched per row (Has cell 5 / 6 on each — Figma cannot link one switch to nested rows), so keep them consistent
  • Padding space/8 (the bar’s radius 8 then sits concentric in the outer 16)
  • Rows sit FLUSH — no gap between them, and none under the header bar: a hover or selection wash runs from the divider above to the row’s own. The space a row needs is inside the row — the slide cell’s padding is space/16, so the 59 pitch is kept, the product row is 46, and a row-header pill is inset space/4 so stacked pills stay 8 apart
  • Columns fill the width — no void at the right end of a row; give a fixed column an explicit width that fits its longest value
  • Numbers right, words left; the entity column is named what the product calls it — MAFO’s header says Publisher
  • On a product dashboard the bar is the NEUTRAL one — the multicolor mode’s neutral-800 bar on neutral-200 pills, the black one of the four; the deck keeps its accent bars
  • A divider is a STRAIGHT line from end to end — its own rectangle under the cell, never a stroke that follows the cell’s rounded ends (the CSS part draws it as ::after over a transparent border for the same reason)
  • 1200 wide for the specimen (1792 on a slide — the content width); FILL in a Card slot or the page

Use when rows of records with the same fields — publishers, campaigns, offers, users; a SWOT or a quarter plan on a slide.

Do not use when fewer than three rows or two columns (a Bullet list or a KPI row); the rows need sorting, filtering, paging or selection (Data table); the values want a chart (Chart recipes); a comparison of two things (a Card pair).

Relates to Table row, Table cell, Data table, Badge, Card, Chart recipes.

Anti-patterns zebra stripes · a coloured cell for status · numbers left-aligned · a header that is not the first row · vertical grid lines · a white table with a grey header · more than seven columns without a Data table.

Keywords: table, grid, rows, columns, data, list of records, SWOT, comp-table

Figma — page Table: Table (2 variants) · Table row (8 variants) · Table cell (12 variants)

shadcn: table

The class, the parts, and nothing that is not in the package. The same block opens table.css.

<div class="pui-table"><table class="pui-table__table">
<thead><tr class="pui-table__row"><th class="pui-table__cell pui-table__cell--header">Publisher<span class="pui-icon pui-table__sort">…</span></th>
<th class="pui-table__cell pui-table__cell--header pui-table__cell--right">Revenue</th></tr></thead>
<tbody><tr class="pui-table__row"><td class="pui-table__cell pui-table__cell--row-header"><span class="pui-table__pill">Q1</span></td>
<td class="pui-table__cell pui-table__cell--right">$ 8 969 916</td></tr>
<tr class="pui-table__row" aria-selected="true"> … </tr></tbody></table></div>
<div class="pui-data-table"><div class="pui-data-table__toolbar">…</div><div class="pui-table">…</div>
<div class="pui-data-table__footer"><span class="pui-data-table__range">1–5 of 118 publishers</span><nav class="pui-pagination">…</nav></div></div>
What it is Note
Size (none) product · --slide (on .pui-table) —
Cell __cell (body) · __cell--header · __cell--row-header (holds a __pill) · __cell--right —
Row :hover · selected = [aria-selected=“true”] or --selected —
Accent data-accent on the table or a parent drives the bar and the pills — table/header/bg and table/header/pill-tint re-resolve per mode (blue navy · red · yellow · multicolor = a neutral-800 bar on neutral-200 pills, the black one); a product dashboard’s table is the neutral one (data-accent=“multicolor” on .pui-table) —

Every number here is measured on the rendered component: contrast (npm run contrast:render), the focus ring (npm run focus) and the keyboard (npm run keyboard). The floors are principle 12’s.

ink on ground reads floor the matrix calls it
#544d4d on #dad9d9 5.85 4.5 text.muted on ground.card.sunken (promised) ok
#0b0202 on #dad9d9 14.56 4.5 text.default on ground.card.sunken (promised) ok
#ffffff on #231b1b 16.88 4.5 text.on-accent on surface.inverse (not-offered) ok
#0b0202 on #e9e9fb 17.1 4.5 KPI value, blue tile (promised) ok
#0b0202 on #f2f2f7 18.38 4.5 text.default on surface.card (promised) ok
#ffffff on #0c0b41 18.42 4.5 Table header label (promised) ok

6 distinct pair(s) rendered, 0 that axe calls a violation.

Nothing in this component takes focus.

Nothing in this component claims an ARIA role with a keyboard contract; its controls are ordinary ones and the browser already gives them their keys.

Tab order across the whole library is document order over 344 stops, and Shift+Tab is its exact reverse — no keyboard trap anywhere (WCAG 2.1.2).

Pepper UI v1.5.0

The Mobupps design system. 386 tokens, 88 components, 65 pages in the workshop — every page of this site generated from the repository, so nothing here is typed twice.