Skip to content

Find what you need, instantly

Search components, ARIA roles & attributes, and WCAG criteria.

Data Display

Table

A sortable, read-only data table with proper headers, scope, and caption — static content the user reads, not a widget they operate cell-by-cell.

Last verified against WCAG 2.2 and WAI-ARIA APG 1.2 on 2026-07-02.

Implementation

Team members and their current account status
RoleLast active
Amara OkaforEngineerActive2026-07-01
Diego FuentesProduct ManagerInvited
Priya NatarajanDesignerActive2026-06-29
Sofia MarchettiSupportActive2026-07-02
Wren CallahanEngineerSuspended2026-05-14
table-pattern.tsx (sort logic)
function toggleSort(key) {
  if (key !== sortKey) { setSortKey(key); setSortDirection("ascending"); return; }
  setSortDirection(prev =>
    prev === "ascending" ? "descending" : prev === "descending" ? "none" : "ascending"
  );
}

<th scope="col" aria-sort={ariaSortFor("name")}>
  <button
    onClick={() => toggleSort("name")}
    aria-label={`Sort by Name, ${sortLabelText}`}
  >
    Name <SortIcon />
  </button>
</th>

/* aria-sort lives on the <th> itself, not the button — that's where
   assistive tech looks for a column's current sort state. The button
   inside is what makes the control keyboard-operable. */

For an interactive tabular widget — editable, selectable, or arrow-key-navigable cells — see the Grid pattern (role="grid") instead.

Live demo

Team members and their current account status
RoleLast active
Amara OkaforEngineerActive2026-07-01
Diego FuentesProduct ManagerInvited
Priya NatarajanDesignerActive2026-06-29
Sofia MarchettiSupportActive2026-07-02
Wren CallahanEngineerSuspended2026-05-14

Required roles, states & properties

Required roles, states, and properties
ElementAttributeWhy
<table><caption>Gives the table an accessible name/purpose announced before a screen reader user enters it (not itself an ARIA attribute, but the required native equivalent).
Column header <th>scope="col"Associates the header with every cell in its column, so jumping to any cell also announces the relevant column label.
Row header <th>scope="row"Associates the header with every cell in its row, giving row context (e.g. person's name) alongside any cell value.
Sortable column <th>aria-sort="ascending" | "descending" | "none"Communicates the column's current sort state. Lives on the header cell, updated dynamically as sort changes — never left stale.
Sort controlReal <button> inside the <th>, with a composed aria-labelKeeps the control keyboard-operable and gives it an unambiguous accessible name like "Sort by Name, currently sorted ascending" instead of just the icon or a bare column label.

Keyboard interaction model

Keyboard interaction model
KeyBehavior
Tab / Shift+TabMoves between interactive elements (sort buttons, any row action buttons) in reading order — normal document tab order, nothing custom.
Enter / SpaceActivates the focused sort button, re-sorting the table and updating aria-sort.

A basic sortable table does not need arrow-key grid/cell navigation — that belongs to a spreadsheet-style ARIA grid pattern and is out of scope here. Testers should not expect arrow keys to move between cells in this pattern.

Focus management rules

  • Only interactive elements (sort buttons, row action buttons) are ever in the Tab order — static data cells are never focus stops.
  • Activating a sort button never moves focus away from that button, even though the row order changes underneath it.
  • Column header aria-sort and the button's accessible name are updated together, synchronously with the re-sort, so they never fall out of sync.

WCAG 2.2 success criteria mapping

WCAG 2.2 success criteria that apply to this component
SCNameLevelWhy it applies
1.3.1Info and RelationshipsAStructure and relationships conveyed visually are also programmatically determinable.
2.1.1KeyboardAAll functionality is operable through a keyboard interface with no specific timing.
4.1.2Name, Role, ValueAFor all UI components, name, role, and value are programmatically determinable; states and changes are announced.
4.1.3Status MessagesAAStatus messages can be programmatically determined via role or properties (e.g. aria-live) without receiving focus.

References