Table

Organism

Data grid for rows × columns of structured content. Mirrors Figma node 140-5139 (light) + 5892-39544 (dark) 1:1. Header strip is #F6F6F6 (light) / #2D2D2D (dark) with Body 1 Semi Bold text. Body rows are transparent (the page surface shows through) with Body 1 Medium text. Every cell carries a 5%-alpha hairline border that hashes the grid without competing with content. Body cells typically pair their label with a trailing kebab (⋮) action via the .table-cell + .table-cell-action helpers. The outer .table-wrap clips the corners to 8 px — required because border-radius can't apply to <table> while border-collapse: collapse is in use.

When to use

✅ Do
  • Use for structured data with multiple attributes per row (lists of users, cases, documents)
  • Always wrap in .table-wrap — required for border-radius and overflow on narrow screens
  • Use .td-num for numeric columns to right-align and apply monospace font
  • Use .table-cell-action for the trailing kebab (⋮) button on each row
  • Use <thead> with <th scope="col"> so screen readers can associate cells with headers
❌ Don't
  • Use for a list of items with only one attribute — use a simple list instead
  • Use bare .table without .table-wrap — border-radius won't apply
  • Simulate a header row with bold <td> elements — always use <th>
  • Show more than 8 columns on a single page without a horizontal scroll wrapper

DigiLawyer Patterns

No specific DigiLawyer patterns documented yet — to be added.

Anatomy

A Table is always wrapped in .table-wrap which clips the corners. The table itself uses standard HTML semantics.

NameStatus
Item A
Active
Item B
Pending
  1. 1Scroll wrapper.table-wrap. Required. Clips to 8px radius + handles horizontal overflow.
  2. 2Table.table. Sets collapse, borders, and sizing.
  3. 3Header row<thead><tr><th scope="col">. Coloured bg, Semi Bold text.
  4. 4Body cell.table-cell. Flex row with label + optional action button.
  5. 5Action slot.table-cell-action. Pushes the kebab button to the trailing edge.

Default

A 6-column table with a Header row + 4 Body rows. Each body cell pairs the label with a trailing kebab (⋮) button — the "more actions" affordance Figma calls out on every body cell.

LabelLabelLabel LabelLabelLabel
Label
Label
Label
Label
Label
Label
Label
Label
Label
Label
Label
Label
Label
Label
Label
Label
Label
Label
Label
Label
Label
Label
Label
Label

Structure

The component is a real HTML <table>. Wrap it in a .table-wrap div to round the outer corners. Header cells live in <thead><tr><th>; body cells in <tbody><tr><td>. Use the .table-cell flex wrapper inside a <td> when you want a label + trailing action — display: flex can't sit on the td itself without breaking table layout. Drop the .table-cell-action button when a column doesn't need an action.

HTML
<div class="table-wrap">
  <table class="table">
    <thead>
      <tr><th>Name</th><th>Email</th><th>Role</th></tr>
    </thead>
    <tbody>
      <tr>
        <td>
          <div class="table-cell">
            Adesh Singh
            <button type="button" class="table-cell-action" aria-label="More">
              <svg><use href="#ico-kebab"/></svg>
            </button>
          </div>
        </td>
        <td>adesh@example.com</td>
        <td>Owner</td>
      </tr>
    </tbody>
  </table>
</div>

Composition

Body cells hold any inline content — text, links, badges, tags, status dots. The trailing kebab action is optional; drop the button when a column doesn't need it. Cells without the .table-cell flex wrapper render as plain text + the parent td's padding (use for simple text columns).

NameStatusPlanEmail
Adesh Singh Online Pro adesh@example.com
Jane Doe Idle Free jane@example.com
Mark Patel Offline Pro mark@example.com

States

The base table has no row hover / selected states in the Figma spec — Figma keeps the surface quiet so content stays primary. The one interactive element is the per-cell kebab action, which fades a soft hover background. .is-hover forces the hover visual at rest for documentation; the live :hover pseudo-class handles it in production.

StateKebab
Default
Hover (forced)

Full matrix

Cell content type × row position. Toggle the theme switch in the global header to see every cell under dark tokens — header bg flips #F6F6F6#2D2D2D, body bg stays transparent, all borders flip from 5%-black to 5%-white.

Header text With kebab Numeric Tag Status dot Action
Default row text
With kebab
1,248 Active Online
Long-content row
Long label here
42 Pending Idle
Compact
Item
7 Archived Offline

Responsive

Wrap any .table in .table-wrap to enable horizontal scroll on narrow screens. The wrapper adds overflow-x: auto and smooth momentum scrolling on touch devices. No changes are needed to the table itself.

NameStatusRoleEmailPlanJoined
Adesh SinghActiveOwneradesh@example.comPro1 Jan 2025
Jane DoeIdleAdminjane@example.comFree15 Mar 2025

Frame above simulates a 390 px mobile viewport — scroll the table horizontally.

HTML
<div class="table-wrap">
  <table class="table"></table>
</div>

Accessibility

Attribute / BehaviourValueNotes
Column headers<th scope="col">Always use <th> with scope="col" so screen readers associate cells with headers
Row headers<th scope="row">Use for the first cell of each row when it identifies the row
Caption<caption>Provide a caption that describes the table's content for screen readers
Sortable columnsaria-sort="ascending"Set on <th> to communicate current sort direction
Action buttonsaria-label="More actions for [row name]"Each kebab (⋮) button must include context about which row it acts on
Keyboard — navigateTabFocusable elements inside cells (buttons, links) are in the natural tab order

API

Class / attrOnDescription
.table-wrap<div>Clipping wrapper. Carries the outer 1 px border + 8 px radius (--radius-xs) + overflow: hidden. Required when you want rounded corners — <table> can't have border-radius directly under border-collapse: collapse.
.table<table>The grid. width: 100%, border-collapse: collapse, Body 1 (16/24) typography. Cells get a 5%-alpha hairline border from --table-body-border.
.table thead th<th>Header cell. Background --table-header-bg, text --table-header-text, font-weight Semi Bold (600). Padding 8 / 12 px → row height ~40 px (24 line-height + 16 padding).
.table tbody td<td>Body cell. Background --table-body-bg (transparent), text --table-body-text, font-weight Medium (500). Same padding as header → uniform row height.
.table-cell<div> inside <td>Flex row that aligns a label + trailing action inside a cell. Justify-content defaults to space-between; add .table-cell-end to right-align for action-only columns.
.table-cell-end.table-cellUtility that flips justify-content to flex-end. Use on action-only columns where there's no leading label.
.td-num<td>Numeric-column helper. Applies font-variant-numeric: tabular-nums (so digits align column-by-column) and text-align: right in one shot.
.table-cell-action<button>Per-cell action button — typically the kebab (More) glyph. 24×24 transparent, fades to the header bg on hover. Pair with aria-label describing the action.
.is-hover.table-cell-actionDocumentation helper — forces the hover visual at rest. Not needed in production.
--table-header-bg / -text / -borderTokenHeader strip bg, label text, and border. Border is a 5% alpha hairline in both modes.
--table-body-bg / -text / -borderTokenBody row tokens. Body bg is transparent in both modes so the table reads on top of the page surface.