j3w1 / TableVue · HTML · React · Astro

J3W1 / DESIGN SYSTEM

Table

A native data table with a header rule, row dividers, hover and selection fills, sortable headers with a glyph, and static empty and loading rows.

stable · LIGHT DOM · 1.1.0

Light DOM retains static content, native semantics, label relationships and host composition without duplicating controls.

Live variants

default

Project records · synthetic fixture
Atlas libraryAvery KimReady24
Orion workspaceJordan LeeIn progress12
Field notesMorgan NoorReady38
Signal monitorRiley StoneReview6

<j3w1-table id="example-table-default"><div class="table-scroller" tabindex="0" role="region" aria-label="Project records"><table class="table"><caption class="table-caption">Project records · synthetic fixture</caption><thead class="table-head"><tr><th class="table-header" scope="col"><button class="table-sort" type="button">Project<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th><th class="table-header" scope="col"><button class="table-sort" type="button">Owner<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th><th class="table-header" scope="col"><button class="table-sort" type="button">Status<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th><th class="table-header" scope="col"><button class="table-sort" type="button">Scope<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th></tr></thead><tbody class="table-body"><tr class="table-row" id="example-table-default-record-0" data-status="Ready"><td class="table-cell" id="example-table-default-record-name-0">Atlas library</td><td class="table-cell">Avery Kim</td><td class="table-cell">Ready</td><td class="table-cell">24</td></tr><tr class="table-row" id="example-table-default-record-1" data-status="In progress"><td class="table-cell" id="example-table-default-record-name-1">Orion workspace</td><td class="table-cell">Jordan Lee</td><td class="table-cell">In progress</td><td class="table-cell">12</td></tr><tr class="table-row" id="example-table-default-record-2" data-status="Ready"><td class="table-cell" id="example-table-default-record-name-2">Field notes</td><td class="table-cell">Morgan Noor</td><td class="table-cell">Ready</td><td class="table-cell">38</td></tr><tr class="table-row" id="example-table-default-record-3" data-status="Review"><td class="table-cell" id="example-table-default-record-name-3">Signal monitor</td><td class="table-cell">Riley Stone</td><td class="table-cell">Review</td><td class="table-cell">6</td></tr><tr class="table-empty" hidden=""><td class="table-empty-cell" colspan="4">No rows match.</td></tr><tr class="table-loading" hidden=""><td colspan="4">⋯ Loading rows</td></tr></tbody></table></div></j3w1-table>

sticky-header

Project records · synthetic fixture
Atlas libraryAvery KimReady24
Orion workspaceJordan LeeIn progress12
Field notesMorgan NoorReady38
Signal monitorRiley StoneReview6

<j3w1-table id="example-table-sticky-header"><div class="table-scroller" tabindex="0" role="region" aria-label="Project records"><table class="table"><caption class="table-caption">Project records · synthetic fixture</caption><thead class="table-head"><tr><th class="table-header" scope="col"><button class="table-sort" type="button">Project<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th><th class="table-header" scope="col"><button class="table-sort" type="button">Owner<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th><th class="table-header" scope="col"><button class="table-sort" type="button">Status<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th><th class="table-header" scope="col"><button class="table-sort" type="button">Scope<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th></tr></thead><tbody class="table-body"><tr class="table-row" id="example-table-sticky-header-record-0" data-status="Ready"><td class="table-cell" id="example-table-sticky-header-record-name-0">Atlas library</td><td class="table-cell">Avery Kim</td><td class="table-cell">Ready</td><td class="table-cell">24</td></tr><tr class="table-row" id="example-table-sticky-header-record-1" data-status="In progress"><td class="table-cell" id="example-table-sticky-header-record-name-1">Orion workspace</td><td class="table-cell">Jordan Lee</td><td class="table-cell">In progress</td><td class="table-cell">12</td></tr><tr class="table-row" id="example-table-sticky-header-record-2" data-status="Ready"><td class="table-cell" id="example-table-sticky-header-record-name-2">Field notes</td><td class="table-cell">Morgan Noor</td><td class="table-cell">Ready</td><td class="table-cell">38</td></tr><tr class="table-row" id="example-table-sticky-header-record-3" data-status="Review"><td class="table-cell" id="example-table-sticky-header-record-name-3">Signal monitor</td><td class="table-cell">Riley Stone</td><td class="table-cell">Review</td><td class="table-cell">6</td></tr><tr class="table-empty" hidden=""><td class="table-empty-cell" colspan="4">No rows match.</td></tr><tr class="table-loading" hidden=""><td colspan="4">⋯ Loading rows</td></tr></tbody></table></div></j3w1-table>

numeric

Project records · synthetic fixture
Atlas libraryAvery KimReady24
Orion workspaceJordan LeeIn progress12
Field notesMorgan NoorReady38
Signal monitorRiley StoneReview6

<j3w1-table id="example-table-numeric"><div class="table-scroller" tabindex="0" role="region" aria-label="Project records"><table class="table"><caption class="table-caption">Project records · synthetic fixture</caption><thead class="table-head"><tr><th class="table-header" scope="col"><button class="table-sort" type="button">Project<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th><th class="table-header" scope="col"><button class="table-sort" type="button">Owner<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th><th class="table-header" scope="col"><button class="table-sort" type="button">Status<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th><th class="table-header" scope="col"><button class="table-sort" type="button">Scope<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th></tr></thead><tbody class="table-body"><tr class="table-row" id="example-table-numeric-record-0" data-status="Ready"><td class="table-cell" id="example-table-numeric-record-name-0">Atlas library</td><td class="table-cell">Avery Kim</td><td class="table-cell">Ready</td><td class="table-cell">24</td></tr><tr class="table-row" id="example-table-numeric-record-1" data-status="In progress"><td class="table-cell" id="example-table-numeric-record-name-1">Orion workspace</td><td class="table-cell">Jordan Lee</td><td class="table-cell">In progress</td><td class="table-cell">12</td></tr><tr class="table-row" id="example-table-numeric-record-2" data-status="Ready"><td class="table-cell" id="example-table-numeric-record-name-2">Field notes</td><td class="table-cell">Morgan Noor</td><td class="table-cell">Ready</td><td class="table-cell">38</td></tr><tr class="table-row" id="example-table-numeric-record-3" data-status="Review"><td class="table-cell" id="example-table-numeric-record-name-3">Signal monitor</td><td class="table-cell">Riley Stone</td><td class="table-cell">Review</td><td class="table-cell">6</td></tr><tr class="table-empty" hidden=""><td class="table-empty-cell" colspan="4">No rows match.</td></tr><tr class="table-loading" hidden=""><td colspan="4">⋯ Loading rows</td></tr></tbody></table></div></j3w1-table>

with-caption

Project records · synthetic fixture
Atlas libraryAvery KimReady24
Orion workspaceJordan LeeIn progress12
Field notesMorgan NoorReady38
Signal monitorRiley StoneReview6

<j3w1-table id="example-table-with-caption"><div class="table-scroller" tabindex="0" role="region" aria-label="Project records"><table class="table"><caption class="table-caption">Project records · synthetic fixture</caption><thead class="table-head"><tr><th class="table-header" scope="col"><button class="table-sort" type="button">Project<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th><th class="table-header" scope="col"><button class="table-sort" type="button">Owner<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th><th class="table-header" scope="col"><button class="table-sort" type="button">Status<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th><th class="table-header" scope="col"><button class="table-sort" type="button">Scope<span class="table-sort-glyph" aria-hidden="true">↕</span></button></th></tr></thead><tbody class="table-body"><tr class="table-row" id="example-table-with-caption-record-0" data-status="Ready"><td class="table-cell" id="example-table-with-caption-record-name-0">Atlas library</td><td class="table-cell">Avery Kim</td><td class="table-cell">Ready</td><td class="table-cell">24</td></tr><tr class="table-row" id="example-table-with-caption-record-1" data-status="In progress"><td class="table-cell" id="example-table-with-caption-record-name-1">Orion workspace</td><td class="table-cell">Jordan Lee</td><td class="table-cell">In progress</td><td class="table-cell">12</td></tr><tr class="table-row" id="example-table-with-caption-record-2" data-status="Ready"><td class="table-cell" id="example-table-with-caption-record-name-2">Field notes</td><td class="table-cell">Morgan Noor</td><td class="table-cell">Ready</td><td class="table-cell">38</td></tr><tr class="table-row" id="example-table-with-caption-record-3" data-status="Review"><td class="table-cell" id="example-table-with-caption-record-name-3">Signal monitor</td><td class="table-cell">Riley Stone</td><td class="table-cell">Review</td><td class="table-cell">6</td></tr><tr class="table-empty" hidden=""><td class="table-empty-cell" colspan="4">No rows match.</td></tr><tr class="table-loading" hidden=""><td colspan="4">⋯ Loading rows</td></tr></tbody></table></div></j3w1-table>

Install and register

Use the exact version. If npm publication is pending, install the release tarball from the installation guide.

npm install --save-exact @j3w1/ui@1.1.0
import '@j3w1/ui/tokens.css';
import '@j3w1/ui/styles/table.css';
import '@j3w1/ui/register/table';

Insert the maintained markup above after loading these imports. Its native children provide accessible names and form behavior; the empty custom tag alone does not create a control.

Vue SFC, React, Astro and plain HTML integration →

Copy the complete implementation

npx --package=@j3w1/ui@1.1.0 j3w1-ui copy table --out ./vendor/j3w1/table

The CLI verifies every file before writing and refuses overwrites. Serve the output over HTTP and open index.html. Keep its modules, CSS, tokens and licence notices together.

Public API

attributes

NameType / signatureMeaning
disabledCustomEventDisable the native controls owned by this instance.
loadingCustomEventMark the primary control busy and prevent duplicate activation.

properties

NameType / signatureMeaning
disabledbooleanDelegates disabled state to native children.
namestringNative control name; application form keys remain explicit.

methods

NameType / signatureMeaning
refresh(): voidReconnect behavior after replacing native child structure.
focus(options?: FocusOptions): voidFocus the first usable native control.
sort(column: number, direction?: 'ascending' | 'descending'): voidSort existing native rows by a column.
filter(query: string): voidFilter existing rows by literal text.

events

NameType / signatureMeaning
j3w1-sortCustomEventThe user requested sorting.
j3w1-selectionCustomEventSelected row identities changed.

Dependencies and verification

Registered components: none. Style dependencies: none.

Package presence establishes an available implementation. Actual passes depend on the tested artifact and environment. Read specification execution evidence; read packed-consumer evidence; inspect the complete state matrix.

Full implementation manifest, API and token dependency closure

Canonical specification

Purpose

Shows records as rows and attributes as columns so they can be compared down a column. The table is for reading; a table with selection checkboxes, resizable columns and a toolbar is the data-table. A single column of rows is a list.

Anatomy

A collapsed native table on color.surface.default with no outer border. The header row is color.text.bright above a 1px color.border.strong rule (2px when the header is sticky, on color.surface.raised); sortable headers wrap their label in a button and show ▲ or ▼ when sorted. Body rows are the row height, separated by 1px color.border.divider, text in color.text.default; numeric cells are end-aligned with tabular numbers. An optional caption in color.text.muted sits above. Two special rows, hidden unless needed, span every column: the empty message and the loading glyph.

States

StateVisualNon-colour channel
defaultrows on color.surface.default; header rule 1px color.border.strong
hoverrow background → color.interaction.hover.bgcursor: default; only on hover-capable pointers
selectedrow fill color.interaction.selection.bg; every cell color.interaction.selection.textaria-selected="true" on the row
selected+focus-visiblethe fill and a ring in color.interaction.focus.ring-container around the rowboth visible at once
selected+container-inactiverow fill color.interaction.selection.inactive-bg with color.interaction.selection.inactive-text; no ringlightness drop between the two fills
sortedthe sorted header shows ▲ (ascending) or ▼ (descending) in color.text.brightaria-sort; the glyph
emptythe body is one full-width cell in color.text.muted: “No rows match.”the message text
loadingthe body is one full-width cell with the static glyph in color.text.muted; the header staysaria-busy="true"; the glyph; no animation

Precedence: loading > empty; selected > hover; focus-visible is always drawn.

Keyboard

A plain table has no row focus: Tab reaches the sort buttons in the header and any control inside a cell. Enter or Space on a sort button cycles ascending, descending. Tables whose rows are targets (row links, row selection) are the data-table and add row focus there.

Accessibility

caption or aria-labelledby names the table; th scope="col" on every header and scope="row" on a row header column. aria-sort on the sorted th, none or absent elsewhere; the glyph is aria-hidden. The empty and loading rows are real rows so the table stays a table; aria-busy="true" on the table while loading and a live region for the outcome. Contrast: body text 8.43:1, header 10.10:1, caption and empty message 5.66:1, selected text 12.47:1 on the fill, inactive 7.02:1, ring 7.48:1 on the fill, sort ring 4.57:1. Rows are at least 24 CSS pixels tall; sort buttons fill the header cell.

Portability

Row backgrounds, one border under the header, one between rows, an outline on a selected row. Toolkits with a native table view take the rule, the divider and the two fills. Hosts that cannot draw an outline on a row draw the ring as an inset 1px border and record it.

Non-examples

Zebra striping. A rounded or bordered table frame. A selected row marked by a left bar (that is navigation, not selection). Header text in caption size or uppercase. Sorting shown by colour alone without aria-sort and a glyph. An animated spinner while loading. An empty state that removes the header. Text truncated with no way to read the full value. A hover fill on a touch device.

j3w1 / command

  • SPEC Overview
  • SPEC Foundations
  • SPEC Components
  • SPEC Patterns
  • SPEC Tokens
  • SPEC Tools
  • SPEC Implement
  • SPEC For agents
  • SPEC Ports
  • SPEC Releases
  • DEMO Vue application demo
  • SPEC Complete UI theme specification