2.5.2 `components/ui/TreeTable` primitive (accessible tree-grid)
Estimate: 18m
The reusable, design-system primitive the list route composes — there is NO table primitive in components/ui/* today (JobsDashboard / WorkflowEditor each hand-roll a local <table>; this is the shared one). A generic, presentational TreeTable: typed columns (header + per-row cell render) and a nested rows model with expand/collapse, indentation by depth, a per-row chevron (leaf rows show none — matching the mockup), sticky header, and a whole-row link target. Pure presentation: it takes already-shaped data + render-props and emits no queries.
Accessibility is the load-bearing requirement. Implement the WAI-ARIA treegrid pattern: role="treegrid", rows with aria-level / aria-expanded / aria-posinset / aria-setsize, roving focus, and keyboard support (Up/Down move, Right expand / move-in, Left collapse / move-out, Enter opens the row). Themed entirely off --el-* tokens (header text --el-text-secondary, row hover hover:bg-(--el-surface) on the ROW not a page surface, borders --el-border); add a /tokens/tree-table specimen joined to the shell-a11y sweep. Match the mockup's spacing, the uppercase column captions, and the row density.
Acceptance criteria
- Generic
TreeTable<Row>with typed columns + nested rows; renders header + indented, expandable rows matchingtree.png(chevron only on parents, type-icon/identifier/title in the TITLE cell via render-prop). - Full treegrid a11y:
role="treegrid",aria-level/expanded/posinset/setsize, roving tabindex, arrow-key expand/collapse/move, Enter activates the row link; axe-clean on the specimen. - Colours via
--el-*only (no Tier-0 utilities); row hover tints the row, never a page surface (finding #35). - Presentational only — no data fetching, no Server-Action imports; expand/collapse state is controllable by the consumer.
- Component test (happy-dom): nesting + indent, expand/collapse toggles children +
aria-expanded, keyboard move/expand;/tokens/tree-tablein the strict shell-a11y sweep.
Context refs
design/work-items/tree.png(+tree.pen) — layout / density / column captions (open it FIRST; inspect all 3 panels)components/issues/ChildList.tsx(2.4.3) +ISSUE_TYPE_META/IssueTypeIcon/Pill— the row vocabulary to reusecomponents/ui/Combobox.tsx(2.3.4) — the project's hand-rolled WAI-ARIA + roving-tabindex reference;app/globals.css--el-*tiers;/tokensroute conventionmotir-core/CLAUDE.md—--el-*token rule