skrewww

Content & Data

Table

Table is a native HTML table foundation with captions, headers, body rows, footers, cell alignment, responsive overflow, RTL support, print-friendly scrolling, and composition patterns for empty/loading/error — not the interactive Data Table pattern (no sorting, selection, or pagination).

Compound semantic foundation — no density/sort/selection variants in Beta

betaReact AvailableFigma UnavailableDocs Partial
React last updated
2026-07-13
Documentation last updated
2026-07-13
Accessibility target
WCAG 2.2 AA (target)
Version
0.1.1-beta

Known open questions

  • Figma component-set node ID unresolved — live MCP verification pending.
  • Temporary table geometry and scroll-shadow tokens await Figma confirmation.
  • Data Table (implemented 2026-07-15) composes Table for the narrow MVP scope approved 2026-07-13 — sorting only, external Pagination; selection, sticky headers, and density remain excluded from v1.

Live preview

Table is a native HTML foundation. It does not sort, select, paginate, or fetch data — compose those patterns separately, or wait for Data Table (sorting-only MVP scope approved, not yet implemented).

Projects

Active projects
ProjectOwnerStatusUpdatedBudgetActions
AtlasUsman FarooqiActive11 Jul 2026$24,000
North StarMaya ChenBeta8 Jul 2026$18,500
Harbor Analytics with a long project title for overflowJordan LeePaused2 Jul 2026$9,250
Total$51,750

Screen-reader caption

Keep a native caption even when it is visually hidden. Prefer caption over duplicating the same text as aria-label on the table.

Visually hidden caption remains accessible

Quarterly budget summary
CategoryAmount
Design systems$12,000
Documentation$4,500

Multi-level headers

Native colSpan, rowSpan, id, and headers attributes pass through — no column-definition API on Table.

Grouped metrics

Project spend versus budget
ProjectFinancialsActions
BudgetSpend
Atlas$24,000$19,400

Interactive cells

Compose Checkbox, Link, Badge, and Menu inside cells. The row stays a non-interactive tr.

Review queue

Items awaiting review
SelectItemStatusActions
AtlasNeeds review

Empty, loading, and error composition

Table has no empty, loading, or error props. Compose Empty State, Skeleton, and Alert with full-width cells and keep headers when useful.

Empty

Archived projects
ProjectOwnerBudget

No archived projects

Archived work will appear here once a project is moved out of the active set.

Loading

Loading project inventory
ProjectOwnerBudget

Error

Last known projects
ProjectBudget
Atlas$24,000

RTL sample

Alignment uses logical start/end. Horizontal overflow and edge fades follow writing direction.

dir=rtl

مشاريع نشطة
المشروعالميزانيةالإجراءات
Atlas$24,000

Shape and surface smoke

Container radius follows shape tokens

Pill container sample
TokenValue
RadiusContainer-capped — not a capsule

Glass surface

Glass surface sample
SurfaceNote
GlassHeader and footer remain distinct
FooterUses footer surface alias

Purpose

A native HTML table foundation for presenting multi-column data with captions, headers, body rows, footers, cell alignment, responsive overflow, RTL-safe alignment, and print-friendly scrolling.

Anatomy

TableScrollArea (optional) + Table + TableCaption + TableHeader/Body/Footer + TableRow + TableHead/TableCell. Multi-level headers via native colSpan/rowSpan/headers. Empty/loading/error via composition, not Table props.

Variants and states

layout-auto · layout-fixed

When to use

Tabular data with aligned columns — statuses, budgets, inventories, comparison matrices — when List Item cannot express the structure.

When not to use

Single-column activity feeds or contact lists — use List Item. Table itself still does not orchestrate selection, pagination ownership, or spreadsheet navigation — sorting now ships as the Data Table pattern (DataTableSortHeader + useDataTableSort), which composes Table rather than replacing it.

Accessibility

Uses native <table>, <caption>, <thead>, <tbody>, <tfoot>, <tr>, <th>, and <td>. Do not add role="grid". Consumer supplies scope on TableHead. Captions name the table; scroll regions use a distinct accessibleLabel when labelled. Interactive cell content must remain real links/buttons/checkboxes. tabIndex on TableScrollArea is consumer-controlled — recommend tabIndex={0} only for known horizontal overflow.

Keyboard behavior

No composite keyboard model. Tab moves to interactive descendants only. Arrow keys are not captured. TableScrollArea tabIndex is consumer-controlled — recommend tabIndex={0} for known horizontal overflow. Spreadsheet-style cell navigation is out of scope — Data Table does not use role="grid".

Common mistakes

Treating Table as Data Table; making entire rows clickable; omitting captions; duplicating caption text as the scroll-region label; using role="grid" for ordinary tabular UI; transforming rows into cards on mobile; forcing tabIndex={0} on every small table; truncating critical data behind Tooltip-only access.

Properties

Compound API: Table, TableCaption, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell, TableScrollArea. layout auto|fixed. Caption visibility visible|screen-reader. Cell/head align start|center|end. data-table-wrap=nowrap for action cells. Empty/loading/error via composition only.

What is the difference between Table and Data Table?

Table is a semantic presentational foundation. Data Table is the higher-level interaction pattern that composes Table — its narrow MVP scope (sorting only, external Pagination) was approved 2026-07-13 and implemented 2026-07-15.

Why does Table use native HTML?

Native table elements provide captions, header associations, and screen-reader navigation without redundant ARIA roles.

Does Table use role="grid"?

No. Ordinary tabular UI uses native HTML table elements. role="grid" is reserved for spreadsheet-like cell navigation and is not part of this foundation.

When should a table include a caption?

Always provide a meaningful caption that describes the table’s purpose. Use visibility="screen-reader" when a visible caption is visually redundant. Do not replace caption with aria-label by default.

How should row headers be marked?

Use TableHead with scope="row" for the identifying column. Table does not infer scope automatically.

Can cells contain buttons and links?

Yes. Compose real Link, Button, Menu, Checkbox, and Badge elements. Keep the row non-interactive.

How does Table work on mobile?

TableScrollArea owns horizontal overflow with Temporary edge fades. Rows do not transform into cards. Native table structure remains intact.

Does Table support sorting?

No — sorting is unsupported on Table itself. Sorting is the MVP interactive pillar Data Table (which composes Table) implemented for its approved scope.

Does Table support row selection?

No selection API. Consumers may place Checkbox controls inside cells as composition only.

When should a true ARIA Grid be used?

Only for spreadsheet-like cell navigation with managed focus. Conventional data tables should stay native HTML and compose Table.

Tokens used

semantic/surface/defaultsemantic/surface/elevatedsemantic/border/defaultsemantic/text/primarysemantic/text/secondarysemantic/focus-ring

Known limitation

React-first foundation audited 2026-07-13. Live Figma verification pending — no component-set node ID. Selection, sticky headers, density, and striped rows remain deferred (sorting is now available via the Data Table pattern). See docs/architecture/table-foundation.md.

Component API

PropTypeDefaultDescription
layout"auto" | "fixed""auto"Table layout algorithm.
TableCaption.visibility"visible" | "screen-reader""visible"Caption visibility while remaining accessible.
TableHead.align / TableCell.align"start" | "center" | "end""start"Logical text alignment via CSS — not HTML align.
TableScrollArea.accessibleLabelstringNames the overflow region when horizontal scrolling needs a landmark. Keep distinct from the caption.
TableScrollArea.tabIndexnumberConsumer-controlled. Recommend 0 for known horizontally scrollable tables; omit when the table fits.
data-table-wrap"nowrap"Optional attribute on TableHead/TableCell to prevent wrapping (action columns).

React example

Copy React example
import {
  Table,
  TableBody,
  TableCaption,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
  TableScrollArea,
} from "@/components/ui/Table";

export function Example() {
  return (
    <TableScrollArea accessibleLabel="Scrollable projects table" tabIndex={0}>
      <Table>
        <TableCaption>Active projects</TableCaption>
        <TableHeader>
          <TableRow>
            <TableHead scope="col">Project</TableHead>
            <TableHead scope="col" align="end">
              Budget
            </TableHead>
          </TableRow>
        </TableHeader>
        <TableBody>
          <TableRow>
            <TableHead scope="row">Atlas</TableHead>
            <TableCell align="end">$24,000</TableCell>
          </TableRow>
        </TableBody>
      </Table>
    </TableScrollArea>
  );
}