Components / structure

Treegrid

Sharing data-se="grid" with DataGrid is the anatomy being shared rather than a name collision: two components, one stylesheet, and the roles stay distinct.

Rendered from the package · open on its own

Summary

A grid whose rows form a hierarchy — a file listing with sizes, a nested budget.

APG patternTreegrid
Built onnative elements
Statusstable
Since0.1.0
<Treegrid label="Files" defaultExpanded={['images']}
  columns={[{ key: 'name', label: 'Name' }, { key: 'size', label: 'Size' }]} rows={…} />

Anatomy

A table carrying role="treegrid". It renders data-se="grid" so one set of rules dresses it and DataGrid alike.

PartElementRequired
cell<td>yes
columnheader<th>yes
row<tr>yes
twisty<svg>yes
twisty-button<button>yes

Properties

PropertyValuesDefaultWhat it does
columnsTreegridColumn[]requiredThe columns, in display order. The first carries the name and the hierarchy.
rowsTreegridRow[]requiredThe rows, nested by children. Unlike a Tree, the nesting is not in the DOM — a treegrid is a flat table, which is why every row carries its own level.
labelstringrequiredNames the grid.
defaultExpandedstring[]noneWhich rows start expanded, by id.
pageSizenumber10Rows moved by Page Up and Page Down. APG leaves this to the author.

States

StateExpressed as
Focused:focus-visible
Selectedaria-selected

Behavior

The two-dimensional grid keyboard plus the tree's expand rules, and the join is the hard part. Right expands a collapsed row when focus is in the first column, but moves a cell everywhere else. Left collapses, or moves back a cell.

Home and End move within the row; Ctrl with either moves within the grid and keeps the column.

Accessibility

Rows carry aria-level, aria-posinset and aria-setsize, unlike Tree. A treegrid is a flat table — the DOM does not carry the hierarchy, so the attributes are the only place it exists.

Branch rows carry an expanded marker. They did not until the upstream port found it, though Tree items always had one.

One tab stop for the whole grid.

Keyboard

KeyResult
Arrow keysMove one cell in two dimensions
Arrow RightExpands a collapsed row when focus is in the first column; moves a cell everywhere else
Arrow LeftCollapses, or moves back a cell
Home / EndJump within the row
Ctrl + Home / EndJump within the grid, keeping the column
Page Up / Page DownMove by a screen
EnterActivates the cell

Roles, states and properties

AttributeSet by
aria-expandedset at render
aria-hiddenalways true
aria-labelset at render
aria-levelset at render
aria-posinsetset at render
aria-setsizeset at render
rolealways treegrid, always row, always columnheader, always gridcell

Focus

One tab stop. The join between the grid keyboard and the tree's expand rules is the hard part — the same arrow means two things depending on the column.

Screen reader

Not recorded as verified. Stage 4 of the readiness ladder — driving each component with VoiceOver and NVDA — is unstarted across the package, and no component should claim otherwise until docs/journal/ records the session that did it.

Contrast and target size

npm run check:contrast audits every color pair this component uses across all four skins, light and dark, and fails the build on a shortfall. Two waivers are on the record in docs/audit/DEFERRED.md.

It sets no target size of its own; anything interactive inside it brings its own.

Tested

  • test/apg/batch-c.test.jsx
  • test/apg/batch-e.test.jsx
  • test/browser/axe.spec.mjs
  • test/browser/keyboard.spec.mjs
  • test/browser/site.spec.mjs
  • test/browser/upstream-combobox.spec.mjs
  • test/browser/upstream-composites.spec.mjs
  • test/browser/upstream-forms-menubar.spec.mjs
  • test/browser/upstream-overlays.spec.mjs
  • test/browser/upstream-toolbar-tree.spec.mjs

Known gaps

_No upstream requirement is recorded as not applicable._

Appearance

TokenUsed for
--se-accent-softbackground
--se-borderborder, border-block-end
--se-border-widthborder, border-block-end
--se-focus-coloroutline
--se-focus-widthoutline, outline-offset
--se-radius-mdborder-radius
--se-space-2gap, padding
--se-space-3padding
--se-space-4padding-inline-start
--se-surface-selectedbackground
--se-surface-sunkbackground
--se-textcolor
--se-text-mutedcolor
--se-text-smfont-size

Motion

None.

Content

The first column carries the name and the hierarchy; the rest carry values. A column whose meaning depends on the row's depth belongs in the first one.

Usage

When not to use it. If the rows carry no columns, that is a Tree. If they carry columns but no hierarchy, that is a DataGrid — or a DataTable if the cells are only read.

Notes

Sharing data-se="grid" with DataGrid is the anatomy being shared rather than a name collision: two components, one stylesheet, and the roles stay distinct.