Designer view
Tree Grid
An interactive 2D data structure with hierarchical rows — the APG escalation from `Grid` for surfaces where rows have parent- child relationships and per-row expand / collapse semantics. Carries `role="treegrid"` on the root, `role="row"` with `aria-level` plus `aria-expanded` (on parent rows) per row. Inherits the grid keyboard model (roving-tabindex, 2D arrow navigation, F2 / Enter / Escape edit-mode lifecycle) and adds ArrowRight / ArrowLeft for tree-navigation: ArrowRight expands a collapsed parent or moves to first child; ArrowLeft collapses an expanded parent or moves to parent.
Also called Tree table Hierarchical grid Expandable data grid
When to use
Use
For tabular data where rows have parent-child relationships AND multiple attribute columns matter — file managers showing name + size + modified-date with folder-nesting, org charts with role + manager + headcount per row, project breakdown structures with task + assignee + status per node, nested budgets with category + amount per row. Use the static variant when cells are interactive but not editable; the editable variant when cells transition to input-mode for in-place editing.
Avoid
For flat tabular data without hierarchy — that is `Grid` (interactive cells without parent-child) or `Table` (read- only data display). For hierarchical single-column data without tabular metadata — that is the APG Tree pattern (separate canonical entry, future). For non-tabular hierarchical layouts (sidebar trees, file-only trees) — use a tree pattern, not a tree grid; the column overhead is pure cost without benefit. For deeply-nested hierarchies where users primarily drill down (5+ levels) — consider breadcrumb-driven navigation between flat lists rather than expanding a single deep tree.
Versus related
- grid-pattern
`Grid` is the flat 2D structure with cells in rows and columns; `TreeGrid` adds hierarchical row semantics — `aria-level` per row, `aria-expanded` on parent rows, ArrowRight / ArrowLeft for tree-navigation. Use Grid when rows are siblings without parent-child relationships; use TreeGrid when rows nest. The keyboard models share the roving-tabindex and 2D arrow-navigation foundation; TreeGrid extends with the expand-collapse semantics on top.
- table
`Table` is read-only flat data display with linear focus through interactive descendants; `TreeGrid` is interactive 2D structure with hierarchical rows and per-row expand-collapse. Use Table when the data is flat and read-only; use TreeGrid when the data is hierarchical AND requires interactive cells (selection, edit, focus-cell-driven drilldown). The escalation cost is significant — TreeGrid's keyboard model (roving-tabindex + arrow-navigation + tree-expand) is the steepest authoring overhead in the canonical canon; reach for it only when the affordances justify the cost.
Tree Grid is the APG-canonical pattern for interactive hierarchical tabular data — file managers with column metadata, org charts, nested budgets, project breakdown structures with cost columns. Distinct from `Grid` (flat 2D cells, no hierarchy) and from a single-column `Tree` (hierarchical rows without tabular columns). The reference documents the `aria-level` / `aria-expanded` / `aria-setsize` / `aria-posinset` contract that makes the hierarchy programmatic, the ArrowRight / ArrowLeft tree-navigation that extends the grid keyboard model, and the visual-indent-driven-by-aria-level pattern that keeps the design surface and the AT semantic in sync.
Figma anatomy
| Slot | Figma type | Hint |
|---|---|---|
root | frame | TreeGrid frame; variant property switches between static and editable shapes |
caption | text | Caption text style; positioned above the treegrid; visibility per "Visible Caption" property |
column-headers-row | frame | Header row container; sticky-position variant per "Sticky Header" property |
column-header | instance | Column header cell instance with sort-affordance variants |
row | instance | Row instance with level / expanded / collapsed / focused / selected variants |
row-expander | instance | Expander icon instance; chevron-right (collapsed) / chevron-down (expanded) variants |
row-indent | frame | Decorative indent spacer; width = aria-level × indent-step |
cell | instance | Data cell instance with default / focused / selected / editing / readonly variants |
row-header | instance | Row header cell instance; hosts row-expander + row-indent for parent rows |
cell-editor | instance | Cell editor instance — input / select / textarea variants per cell-data-type |
selection-overlay | frame | Decorative overlay rectangle; absolute-positioned over selected cell range |
Token usage per slot
caption- color
- foreground
color.text.primary
- foreground
- typography
- size
text.md - weight
weight.semibold
- size
column-header- color
- foreground
color.text.primary
- foreground
- typography
- size
text.sm - weight
weight.semibold
- size
row-expander- color
- foreground
color.text.muted
- foreground
cell- typography
- size
text.sm
- size
Figma ↔ Code property map
| Figma | Kind | Code | Notes |
|---|---|---|---|
Variant | Enum | variant | Maps static / editable. Editable activates F2/Enter/Escape edit-mode lifecycle and cell-editor slot mounting. |
Size | Enum | size | sm / md. |
Multi Select | Boolean | multiSelect | When true, supports multi-cell selection via Shift+Arrow / Ctrl+Click; root carries `aria-multiselectable="true"`. |
Virtualized | Boolean | virtualized | When true, only viewport-visible rows render; requires `aria-rowcount` on root and `aria-rowindex` per rendered row, recomputed as expansion state changes. |
Sticky Header | Boolean | stickyHeader | When true, column-headers-row uses `position: sticky` so headers stay visible during vertical scroll. |
Sortable | Boolean | sortable | Per-column sort affordance plus `aria-sort` on column headers. |
Expanded Keys | Text | expandedKeys | Set of row IDs currently expanded. Pairs with expandChange event for two-way binding. JSON serialization for URL persistence. |
Lazy Load Children | Boolean | lazyLoadChildren | When true, child rows are fetched on parent expansion via async callback; aria-busy="true" on the parent row during fetch. |
Indent Step | Number | indentStep | Per-level indent in pixels. Drives row-indent slot via CSS `padding-inline-start: calc(var(--level) * indentStep)`. Default 24. |
Row Count | Number | rowCount | Total currently-visible row count (for virtualized treegrids); reflects to `aria-rowcount`. Recomputes as expansion state changes. |
Motion
| Transition | Duration token |
|---|---|
expandCollapse | motion.duration.fast |
cellFocusTransition | motion.duration.fast |
editModeEnter | motion.duration.fast |
Responsive behaviour
| Breakpoint | Change |
|---|---|
breakpoint.sm | Below this width, the treegrid keyboard model is hard to use on touch (no arrow keys, no F2 to enter edit-mode, no ArrowRight / ArrowLeft to expand / collapse). The canonical pattern is to escalate to a single-column Tree or to a stacked-card per-row layout on narrow viewports. Editable treegrids on mobile route through tap-to-edit modal flows rather than in-place edit-mode. |
breakpoint.md | At and above this width, the full treegrid keyboard model is active — roving-tabindex, 2D arrow-navigation, ArrowRight / ArrowLeft tree-navigation, F2 / Enter / Escape edit-mode lifecycle. Sticky-header and sticky-first-column activate when the treegrid exceeds the viewport. |
Internationalisation
RTL · mirroring
Column flow follows logical direction — same as Grid. Row-indent uses `padding-inline-start` so the indent flips under RTL: visually right-side under Arabic / Hebrew. Row-expander chevron icons (chevron-right when collapsed, chevron-down when expanded) flip direction under RTL — visually collapsed-state chevron points left in RTL. ArrowRight / ArrowLeft tree-navigation maps to visual direction per APG recommendation; under RTL, ArrowRight collapses (visually moving toward parent at the right) and ArrowLeft expands.
Text expansion
Column headers and row content expand 30-50% under translation (file names and folder names typically don't translate but column headers do — "Name" → "Nome", "Modified" → "Geändert" 100% longer). Long row-content forces wider columns and may push the treegrid past viewport width — the scrollable-region wrapper absorbs this. Cell-editor inputs need flexible sizing for translated values. Indent steps stay constant across locales.
Variants, properties, states
Variants
Structurally different versions of the component.
static editable Properties
The same component, parameterised.
| Property | Type |
|---|---|
size | sm | md |
multiSelect | boolean |
virtualized | boolean |
stickyHeader | boolean |
sortable | boolean |
States
Browser/user-driven (interactive) vs. app-driven (data).
| Kind | States |
|---|---|
interactive | hoverfocus-visibleactive |
data | idleeditinghasSelectionhasSortinghasExpansionloading |
State transitions
| From | To | Trigger |
|---|---|---|
idle | hasExpansion | User activates a row-expander or presses ArrowRight on a collapsed parent row |
hasExpansion | idle | User collapses every previously-expanded row (ArrowLeft on expanded parent) |
idle | editing | User presses F2 or Enter on a focused editable cell (editable variant only) |
editing | idle | User presses Enter (commit) or Escape (cancel) inside the cell-editor |
idle | hasSelection | User activates selection via Space, Shift+Arrow, or Ctrl+Click |
idle | hasSorting | User activates a sortable columnheader via Enter / Space |
idle | loading | Async fetch begins (lazy-load child rows on parent expansion, server-side sort, or filter) |
loading | idle | Async fetch resolves with new data |
Figma↔Code mismatches
- 01 Figma
Indent drawn as fixed-pixel inline padding per row variant
CodeCSS `padding-inline-start: calc(var(--level) * indentStep)` driven by `aria-level`
ConsequenceDesigners compose treegrid rows with explicit indent values per nesting level (level-1: 0px, level-2: 24px, level-3: 48px); developers must compute the indent from `aria-level` so the visual surface and the AT semantic stay in sync. Without explicit anatomy, implementations may ship visual-only indents (sighted users see hierarchy, AT users hear flat row-list) or AT-only `aria-level` (sighted users see no hierarchy, AT users hear levels).
CorrectDocument the row-indent slot as decorative AND explicitly derived from `aria-level`. Figma carries row variants per level with the indent pre-computed; the design surface signals the `aria-level` value as the source-of-truth. Code wires CSS `padding-inline-start: calc(var(--level) * 24px)` where `--level` reflects `aria-level`, OR uses an `aria-hidden` spacer with width computed from level. Visual and AT stay in sync by construction.
- 02 Figma
Expander drawn as decorative chevron with no interaction model
CodeActivation via row-click + ArrowRight/Left + (optionally) `<button>` wrapper around chevron
ConsequenceDesigners ship the expander chevron as a static icon with no documented interaction; developers must wire activation via row-click, keyboard ArrowRight / ArrowLeft, AND optionally a button wrapper for icon-click activation. Without explicit anatomy, the activation model is ambiguous and implementations may ship one pattern (mouse-click chevron only) without the keyboard model (ArrowRight / ArrowLeft on parent row), breaking keyboard accessibility.
CorrectDocument the row-expander as decorative `aria-hidden="true"` AND document the activation contract as a row-level keyboard handler (ArrowRight / ArrowLeft) plus optional `<button>` wrapper for sighted-mouse users. Figma carries the chevron in two states (collapsed / expanded) plus annotation indicating the keyboard activation. Code wires the row-level keyboard handler; the icon stays decorative because `aria-expanded` on the row is the canonical AT signal.
- 03 Figma
Hierarchy drawn as visual nesting only
Code`aria-level` plus `aria-expanded` programmatic semantics on each row
ConsequenceDesigners compose treegrid hierarchy as visual indent + chevron-direction; developers must add `aria-level` per row and `aria-expanded` on parent rows for the AT semantic. Without explicit anatomy, the hierarchy may ship as visual-only — sighted users see nesting, AT users hear a flat row-list. The most common treegrid implementation failure.
CorrectDocument `aria-level` and `aria-expanded` as first-class row attributes in the row slot's a11y hint. Figma carries the level as a row property (Level 1 / 2 / 3 variants) and the expansion state as a separate property (Collapsed / Expanded). Code wires `aria-level="${depth}"` plus `aria-expanded="${isExpanded}"` (omitted on leaf rows); the visual indent and chevron read from the same source.
- 04 Figma
Expanded / collapsed states drawn as separate row arrangements
CodeSingle row with state-driven children visibility — children DOM-mounted only when expanded
ConsequenceDesigners compose collapsed treegrid as one arrangement (parent rows visible) and expanded treegrid as another (parent + child rows visible); developers ship a single composition where child rows mount / unmount per parent `aria-expanded` state. The two surfaces diverge structurally — designer's separate arrangements lose the per-row state bookkeeping, developer's single composition preserves it. Without explicit anatomy, the state-driven mounting may ship as separate virtual-DOM trees (expansion swaps the whole tree, breaking focus + selection state).
CorrectDocument expansion as a per-row state, not a tree-wide variant. Figma carries the row in collapsed / expanded states; child rows are conditionally-visible siblings of the parent row, not a separate composition. Code mounts child rows under parent rows in DOM order; `aria-expanded="false"` plus `display: none` hides them visually while keeping the DOM structure stable for focus + selection.
- 05 Figma
Drag-and-drop reorder drawn as separate user flow
CodeIn-grid keyboard model + drag-handle slot for mouse / touch reordering
ConsequenceDesigners compose tree reordering as a separate "edit hierarchy" mode with explicit reorder controls; developers may ship in-grid drag-and- drop OR keyboard-driven reorder (Alt+ArrowUp / Alt+ArrowDown to move row up / down within siblings). The two surfaces diverge — designer's separate-mode keeps reordering rare, developer's in-grid pattern makes it ambient. Without explicit anatomy, implementations may ship mouse-only drag without keyboard equivalent (WCAG 2.1.1 Keyboard violation for reordering-as-affordance).
CorrectDocument reordering as out-of-canonical-scope OR document the keyboard model explicitly (Alt+ArrowUp / Alt+ArrowDown for sibling- reorder, Alt+ArrowRight / Alt+ArrowLeft for level-change). Reordering is a heavyweight affordance — most production treegrids do not ship it; when they do, the keyboard model must match the mouse drag model for WCAG 2.1.1 compliance.
Contracts
Non-negotiable contracts
APGAPG: TreeGrid pattern aria-level requirement Every row carries `aria-level` (1-based depth, 1 is a top-level row). The level drives both the visual indent and the AT announcement. Implementations that ship visual indent without `aria-level` violate WCAG 1.3.1 — sighted users see hierarchy, AT users hear flat row-list.
Without `aria-level`, the entire hierarchical semantic is invisible to AT. SR users hear "row 1, row 2, row 3" with no indication of which rows are children of which parents. The treegrid degrades to a flat grid with misleading `role="treegrid"`.
APGAPG: TreeGrid pattern aria-expanded requirement Parent rows (rows with descendants) carry `aria-expanded` reflecting the current expansion state — `true` when children are visible, `false` when collapsed. Leaf rows OMIT `aria-expanded` (the absence is the canonical signal that the row has no descendants).
Without `aria-expanded` on parent rows, AT users cannot tell which rows are expandable or whether a row is currently expanded. ArrowRight / ArrowLeft navigation has no programmatic state to observe. The expansion-toggle gesture becomes invisible to AT.
APGAPG: TreeGrid pattern keyboard interaction ArrowRight / ArrowLeft implement tree- navigation on top of the grid keyboard model — ArrowRight expands collapsed parents OR moves to first child of expanded parents; ArrowLeft collapses expanded parents OR moves to parent of leaf rows.
Without the tree-keyboard handlers, keyboard users cannot expand / collapse rows via keyboard — they must mouse- click the chevron, breaking keyboard accessibility. The defining tree- navigation affordance is gone.
APGAPG: TreeGrid extends Grid pattern Inherits Grid's contracts: roving- tabindex (one cell at a time carries `tabindex="0"`), 2D arrow-key navigation, F2 / Enter / Escape edit- mode lifecycle, role-hierarchy consistency (cells inside `role="treegrid"` carry `role="gridcell"` / `role="columnheader"` / `role="rowheader"`), virtualized-aware ARIA attributes (`aria-rowcount` / `aria-rowindex`).
Without inheriting Grid's contracts, the treegrid loses the foundation keyboard model that the tree-navigation extends. The full APG-canonical keyboard model is the union of Grid's plus the tree-extension; partial implementations fail one or both.
Canon Visual indent per row derives from `aria-level` (single source-of-truth) — `padding-inline-start: calc(var(--level) * indentStep)` or equivalent. Visual and AT cannot diverge; both read from the same value.
Without the single-source-of-truth rule, implementations may compute indent from a separate state value (e.g., the row's array-position) and the visual hierarchy diverges from the `aria-level` AT semantic. The canonical discipline keeps them in sync by construction — change the level, the indent updates; AT users and sighted users see the same structure.
Vocabulary drift
- WAI-ARIA
role=treegrid + aria-level + aria-expanded- Canonical ARIA pattern. WAI-ARIA Authoring Practices Guide documents the full keyboard model — inherits Grid's foundation plus the ArrowRight / ArrowLeft tree-navigation. The canonical anatomy mirrors APG directly.
- HTML
<table role="treegrid">- Native HTML `<table>` plus explicit `role="treegrid"` is the canonical hybrid. `<div role="treegrid">` is the fallback for non-tabular layouts (rare for treegrid because tabular columns are the differentiator from Tree).
- AG Grid
AgGridReact with treeData- AG Grid Tree Data is the dominant production treegrid library. Implements the full APG keyboard model, lazy- loading children on expansion, virtualization, edit-mode lifecycle. `getDataPath(row) => string[]` is the canonical tree-shape API; AG Grid derives `aria-level` from path depth.
- React Aria
Table with expandedKeys (tree mode)- React Aria's `Table` ships tree-mode opt-in via `expandedKeys` + `onExpandedChange`. Headless — consumers compose the DOM and visual treatment; React Aria wires `aria-level` / `aria-expanded` plus the keyboard model. The single-component-with-mode- prop reflects the canonical "treegrid extends grid" relationship.
- PrimeVue
TreeTable- PrimeVue ships `TreeTable` as a first- class Vue treegrid primitive with `nodes` (tree-shaped data), `expandedKeys` v-model, `selectionKeys` v-model. Tabular columns are first- class. The naming-only divergence ("TreeTable" vs canonical "TreeGrid") does not affect the API surface.
- Material 3
— (no formal TreeGrid pattern)- Material 3 spec does not include the TreeGrid pattern. Material UI ships `<TreeView>` (single-column tree, not treegrid). For canonical APG-compliant treegrid, Material projects escalate to AG Grid.
- Carbon
— (no formal TreeGrid pattern)- Carbon ships `DataTable` (flat tabular data, Table pattern) and `TreeView` (single-column tree). For canonical treegrid, Carbon projects escalate to AG Grid or build custom on top of DataTable + manual `aria-level` / `aria-expanded` wiring.
- Atlassian
— (no formal TreeGrid pattern)- Atlassian ships `DynamicTable` (Table pattern, flat). No first-class treegrid primitive in @atlaskit. For treegrid use cases, Atlassian projects escalate to AG Grid or build custom.
Common mistakes
#treegrid-no-aria-level
Rows lack `aria-level` (hierarchy invisible to AT)
Rows render with visual indent but no `aria-level` attribute. AT users hear a flat list of rows with no hierarchy semantic — "row 1, row 2, row 3" — when the visual surface shows "Folder A > File 1 > Subfile 1". The hierarchy is invisible to AT entirely. The most common treegrid implementation failure.
Set `aria-level="${depth}"` on every row (1-based, 1 is a top-level row). The level drives both the visual indent (via CSS `padding-inline-start: calc(var(--level) * indentStep)`) and the AT announcement ("row, level 2, ${cellValues}"). The single source- of-truth keeps visual and AT in sync.
#treegrid-no-aria-expanded
Parent rows lack `aria-expanded` (expansion state invisible to AT)
Parent rows render with chevron-right / chevron-down icons but no `aria-expanded` attribute. AT users hear no expansion state and cannot tell which parent rows have visible children. ArrowRight / ArrowLeft navigation has no programmatic state to observe — the expansion-toggle gesture has no AT effect. APG explicit rule violation.
Set `aria-expanded="true"` on parent rows whose children are visible; set `aria-expanded="false"` on collapsed parent rows; OMIT `aria-expanded` on leaf rows (the absence is the canonical signal that the row has no descendants). The visual chevron icon and the `aria-expanded` attribute share the same source-of-truth.
#treegrid-arrow-not-tree-keyboard-model
ArrowRight / ArrowLeft do not expand / collapse parent rows
The treegrid implements the grid keyboard model (cell-by-cell navigation) but ArrowRight / ArrowLeft do not extend it with the tree-navigation semantic — on a collapsed parent, ArrowRight should expand it; on an expanded parent, ArrowRight should move to the first child; ArrowLeft should collapse expanded parents or move to the parent of leaf rows. Keyboard users cannot expand / collapse via keyboard — they must mouse-click the chevron, breaking keyboard accessibility.
Implement the tree-keyboard handlers on top of the grid keyboard model: ArrowRight on a collapsed parent expands; ArrowRight on an expanded parent moves to the first child; ArrowLeft on an expanded parent collapses; ArrowLeft on a child row (or leaf) moves focus to the parent row. Asterisk (*) expands all sibling parent rows. The handlers shift the roving-tabindex along with the focus; the row's `aria-expanded` flips on toggle.
#treegrid-cell-not-gridcell-role
Cells use `<td>` without `role="gridcell"` when root is `role="treegrid"`
The root carries `role="treegrid"` but cells are bare `<td>` without `role="gridcell"`. AT announces the root as a tree grid but cells as plain table cells — role hierarchy broken. SR users hear inconsistent semantics on entry vs cell navigation. Inherits the grid-cell-not-gridcell-role mistake from `Grid`.
When the root is `role="treegrid"`, the cells inside MUST carry `role="gridcell"`, `role="columnheader"`, or `role="rowheader"`. For native `<th>` and `<td>` elements, add the explicit role — implicit table semantics do not propagate through the explicit `role="treegrid"` override.
#treegrid-no-aria-rowcount-virtualized
Virtualized treegrid omits `aria-rowcount` and `aria-rowindex`
The treegrid renders only viewport-visible rows plus a buffer; without `aria-rowcount` on the root and `aria-rowindex` per row, AT reports the rendered count as the total. For treegrids the situation is worse than for flat grids because the rendered count depends on which parent rows are expanded — AT users perceive different row-counts at different expansion states with no indication of the underlying truth.
Set `aria-rowcount="${trueTotal}"` on the root, where `trueTotal` is the count of rows visible at the current expansion state (NOT the count of all rows including collapsed children). `aria-rowindex` per row is the 1-based index within the currently-visible set. Update both as expansion state changes.
#treegrid-when-tree-suffices
TreeGrid pattern used when single-column Tree would work
The component ships with `role="treegrid"` and full tabular columns but the cells have no useful column data — only the row-name column carries content; other columns are empty or carry redundant metadata. The tabular complexity buys nothing; a single- column Tree pattern would suffice.
Use the APG Tree pattern (single-column hierarchical structure, separate canonical pattern) when only one column carries meaningful data. Reserve TreeGrid for surfaces where multiple columns matter (file managers with name + size + date columns, org charts with role + manager + headcount columns). The escalation cost should match the affordance value.
Accessibility hints
| Slot | Accessibility hint | |
|---|---|---|
root | `<table role="treegrid" aria-rowcount="..." aria-colcount="..." aria-multiselectable="...">`. Native `<table>` plus `role="treegrid"` is the canonical hybrid — retains structural HTML semantics while signaling the interactive hierarchical keyboard model. AT users hear "tree grid, N rows, M columns" on entry. | |
caption | `<caption>` inside `<table role="treegrid">` is canonical. SR announces the caption on treegrid entry. Translate per locale. | |
column-headers-row | `<tr role="row">` containing `<th role="columnheader" scope="col">` children. Columnheaders are focusable in the treegrid keyboard model — arrow keys navigate to them like any other cell. | |
column-header | `<th role="columnheader" scope="col" tabindex="-1">`. `aria-sort="ascending"` / `"descending"` / `"none"` when sortable. Same roving-tabindex bookkeeping as Grid. | |
row | `<tr role="row" aria-level="1" aria-expanded="true" aria-setsize="5" aria-posinset="2">` (parent row at depth 1, second of five siblings, currently expanded). For leaf rows omit `aria-expanded` entirely (the absence is the canonical signal that the row has no children). For deep nesting the level-driven indent is the visual surface; the AT semantic comes from `aria-level`. SR announces "row, level 1, expanded, 2 of 5, ${cellValues}". | |
row-expander | `aria-hidden="true"` is the canonical default — the expansion semantic lives on the parent row's `aria-expanded`, not on the icon. SR users hear "expanded" / "collapsed" via the row-level `aria-expanded`, not via the icon's accessible name. Implementations that wrap the icon in `<button>` for mouse-click activation should still mark the inner icon `aria-hidden="true"` and rely on the row- level `aria-expanded` for AT announcement. | |
row-indent | Render via CSS or as `aria-hidden` spacer. SR users do not hear the indent; they hear the `aria-level` value ("level 3"). Implementations that compute indent from anything other than `aria-level` risk visual-vs-AT divergence — always derive indent from the same value AT reads. | |
cell | `<td role="gridcell" tabindex="-1">` for non-active cells; the active cell has `tabindex="0"`. Same roving-tabindex bookkeeping as Grid. `aria-colindex` for virtualized treegrids. Cells in the leading column of parent rows wrap the row-expander + row-indent + cell value; cells in non-leading columns are standard data content. | |
row-header | `<th role="rowheader" scope="row" tabindex="-1">`. SR announces the row-header on cell-by-cell navigation, providing row context the same way columnheader provides column context. For treegrids, the row-header is conventionally the column that carries the row's hierarchical identity (file name, task name, account category). | |
cell-editor | Native `<input>` / `<select>` / `<textarea>` carries the right keyboard model and AT semantics. On edit-mode entry, focus moves to the editor; on Enter / Tab commit, focus returns to the cell; on Escape, the value reverts and focus returns to the cell. Same edit-lifecycle as Grid. | |
selection-overlay | `aria-hidden="true"`. The overlay is visual scaffolding; AT semantic lives on `aria-selected` per cell and per row. |