Tree Grid
Primitive

Tree Grid

Headless hierarchical grid primitives combining tree expansion with grid cell navigation.

Live behavior

Tree Grid in motion

Interactive
Atom behavior · App-owned appearance
Preparing behavior…

Interact with the specimen and inspect the behavior Atom contributes.

waiting for input

When to Use

Use TreeGrid when hierarchical rows expand and each row also contains several navigable columns, such as a file browser with size and modified-date columns. Use Tree for one-column hierarchies and DataGrid when rows are flat rather than parent and child nodes.

Features

The behavior Atom owns before your product adds appearance.

  • Implements role="treegrid" with row, row header, column header, and gridcell parts.
  • Supports controlled and uncontrolled expansion.
  • Supports controlled and uncontrolled active cell state.
  • Supports optional row selection with selectable parent rows.
  • Hides descendant rows when parent rows are collapsed.
  • Supports RTL-aware cell navigation and tree expand/collapse keys through dir and Direction.Provider.
  • Moves an active descendant cell to its collapsed ancestor's tree-column cell when controlled or uncontrolled expansion hides that descendant.
  • Gives actionable column headers equivalent pointer and Enter activation.
  • Keeps sorting, filtering, resizing, editing, and virtualization outside the primitive.

Import

tsx
import { TreeGrid } from "@flowstack-ui/atom";

Anatomy

tsx
<TreeGrid.Root>
  <TreeGrid.Caption />
  <TreeGrid.Header>
    <TreeGrid.Row>
      <TreeGrid.ColumnHeader />
    </TreeGrid.Row>
  </TreeGrid.Header>
  <TreeGrid.Body>
    <TreeGrid.Row>
      <TreeGrid.RowHeader />
      <TreeGrid.Cell />
    </TreeGrid.Row>
  </TreeGrid.Body>
  <TreeGrid.Footer />
</TreeGrid.Root>

API Reference

Root

Owns hierarchical visibility, active-cell navigation, optional row selection, expansion, direction, and the single focus target for the entire grid.

PropTypeDefault
childrenReactNode-
valuestring | string[] | null-
defaultValuestring | string[] | nulldepends on selectionMode
onValueChange(value) => void-
onKeyDown(event) => void-
expandedValuestring[]-
defaultExpandedValuestring[][]
onExpandedValueChange(value: string[]) => void-
activeCell{ rowIndex: number; columnIndex: number } | null-
defaultActiveCell{ rowIndex: number; columnIndex: number } | nullnull
onActiveCellChange(cell: TreeGridCellCoordinates | null) => void-
selectionMode"none" | "single" | "multiple""none"
disabledbooleanfalse
readOnlybooleanfalse
loopbooleanfalse
dir"ltr" | "rtl"Direction.Provider
rowCountnumber-
columnCountnumber-
selectOnRowClickbooleanfalse
renderRenderProp-
asChildbooleanfalse
ARIA attributeValues
role"treegrid"
aria-activedescendantActive cell id when a cell is active
aria-colcountcolumnCount or -1
aria-disabled"true" when disabled
aria-multiselectable"true" when selectionMode="multiple"
aria-readonly"true" when read-only
aria-rowcountrowCount or -1
Data attributeValues
[data-slot]"tree-grid"
[data-active]Present when a cell is active
[data-focused]Present while focus is inside the treegrid
[data-disabled]Present when disabled
[data-readonly]Present when read-only
[data-column-count]Normalized positive columnCount
[data-row-count]Normalized positive rowCount
[data-selection-mode]"single" or "multiple"

Caption

Provides a visible accessible name or description for the treegrid.

PropTypeDefault
childrenReactNode-
renderRenderProp-
asChildbooleanfalse
Data attributeValues
[data-slot]"tree-grid-caption"

Groups header Rows and ColumnHeader cells above the scrollable body.

PropTypeDefault
childrenReactNode-
renderRenderProp-
asChildbooleanfalse
ARIA attributeValues
role"rowgroup"
Data attributeValues
[data-slot]"tree-grid-header"

Row

Registers one hierarchical row, its parent, visibility, expansion, selection, and normalized row index for all cells inside it.

PropTypeDefault
rowIndexnumber-
indexnumber-
valuestringrequired
parentValuestring | nullnull
levelnumber1
expandablebooleanfalse
selectablebooleantrue
disabledbooleanfalse
renderRenderProp-
asChildbooleanfalse
ARIA attributeValues
role"row"
aria-disabled"true" when row or root is disabled
aria-expanded"true" or "false" when expandable
aria-hidden"true" when hidden by a collapsed parent row
aria-levelHierarchical level
aria-rowindexNormalized positive row index
aria-selected"true" or "false" when selection is enabled
Data attributeValues
[data-slot]"tree-grid-row"
[data-expandable]Present when expandable
[data-selectable]Present when selectable and selection is enabled
[data-selection-disabled]Present when not selectable and selection is enabled
[data-expanded]Present when expanded
[data-hidden]Present when hidden by a collapsed parent row
[data-disabled]Present when disabled
[data-parent-value]Parent row value
[data-level]Hierarchical level
[data-row-index]Normalized positive row index
[data-selected]Present when selected
[data-value]Row value

ColumnHeader

Renders a navigable header cell, optional sort state, and the normalized column coordinate used by Root navigation.

PropTypeDefault
childrenReactNode-
columnIndexnumber-
indexnumber-
disabledbooleanfalse
sortDirection"ascending" | "descending" | "none" | "other"-
onAction() => void-
scopenative scope"col"
renderRenderProp-
asChildbooleanfalse
ARIA attributeValues
role"columnheader"
aria-colindexNormalized positive column index
aria-disabled"true" when column header, row, or root is disabled
aria-selected"true" or "false" when selection is enabled
aria-sortsortDirection value
Data attributeValues
[data-slot]"tree-grid-column-header"
[data-active]Present when active and treegrid-focused
[data-disabled]Present when disabled
[data-column-index]Normalized positive column index
[data-selected]Present when row is selected
[data-sort]"ascending" | "descending" | "none" | "other"
[data-actionable]Present when an enabled indexed header has onAction

Body

Groups the visible hierarchical data Rows below Header.

PropTypeDefault
childrenReactNode-
renderRenderProp-
asChildbooleanfalse
ARIA attributeValues
role"rowgroup"
Data attributeValues
[data-slot]"tree-grid-body"

RowHeader

Renders the cell that names its Row. Clicking it focuses the cell and toggles the row when expandable.

PropTypeDefault
childrenReactNode-
columnIndexnumber-
indexnumber-
disabledbooleanfalse
scopenative scope"row"
renderRenderProp-
asChildbooleanfalse
ARIA attributeValues
role"rowheader"
aria-colindexNormalized positive column index
aria-disabled"true" when row header, row, or root is disabled
aria-selected"true" or "false" when selection is enabled
Data attributeValues
[data-slot]"tree-grid-row-header"
[data-active]Present when active and treegrid-focused
[data-disabled]Present when disabled
[data-column-index]Normalized positive column index
[data-selected]Present when row is selected

Cell

Renders a navigable data cell and registers its normalized column coordinate with the current Row.

PropTypeDefault
childrenReactNode-
columnIndexnumber-
indexnumber-
disabledbooleanfalse
renderRenderProp-
asChildbooleanfalse
ARIA attributeValues
role"gridcell"
aria-colindexNormalized positive column index
aria-disabled"true" when cell, row, or root is disabled
aria-selected"true" or "false" when selection is enabled
Data attributeValues
[data-slot]"tree-grid-cell"
[data-active]Present when active and treegrid-focused
[data-disabled]Present when disabled
[data-column-index]Normalized positive column index
[data-selected]Present when row is selected

Groups optional summary Rows after Body.

PropTypeDefault
childrenReactNode-
renderRenderProp-
asChildbooleanfalse
ARIA attributeValues
role"rowgroup"
Data attributeValues
[data-slot]"tree-grid-footer"

Advanced compound parts can use useTreeGridContext and useTreeGridRowContext with their matching public providers.

Examples

Expandable Rows

tsx
import { TreeGrid } from "@flowstack-ui/atom";

export default function PlatformTreeGrid() {
  return (
    <TreeGrid.Root
      defaultExpandedValue={["platform"]}
      aria-label="Platform files"
      columnCount={2}
    >
      <TreeGrid.Header>
        <TreeGrid.Row value="headers">
          <TreeGrid.ColumnHeader columnIndex={1}>Name</TreeGrid.ColumnHeader>
          <TreeGrid.ColumnHeader columnIndex={2}>Type</TreeGrid.ColumnHeader>
        </TreeGrid.Row>
      </TreeGrid.Header>
      <TreeGrid.Body>
        <TreeGrid.Row rowIndex={1} value="platform" expandable selectable={false}>
          <TreeGrid.RowHeader columnIndex={1}>Platform</TreeGrid.RowHeader>
          <TreeGrid.Cell columnIndex={2}>Folder</TreeGrid.Cell>
        </TreeGrid.Row>
        <TreeGrid.Row rowIndex={2} value="api" parentValue="platform">
          <TreeGrid.RowHeader columnIndex={1}>API</TreeGrid.RowHeader>
          <TreeGrid.Cell columnIndex={2}>Folder</TreeGrid.Cell>
        </TreeGrid.Row>
      </TreeGrid.Body>
    </TreeGrid.Root>
  );
}

Accessibility

TreeGrid follows the WAI-ARIA treegrid pattern with Root focus and aria-activedescendant. Provide an accessible name with Caption, aria-label, or aria-labelledby.

KeyDescription
Expand / next-cell arrowExpands a collapsed expandable row, or moves to the next cell: ArrowRight in LTR, ArrowLeft in RTL
Collapse / previous-cell arrowCollapses an expanded row, moves to parent, or moves to the previous cell: ArrowLeft in LTR, ArrowRight in RTL
ArrowDown / ArrowUpMoves between visible rows
Home / EndMoves within a row
Ctrl+Home / Ctrl+EndMoves to first or last visible cell
EnterCalls onAction for an actionable active ColumnHeader; otherwise toggles an expandable tree-column row or selects the active row.
SpaceSelects the active row when selection is enabled.

Changelog

Unreleased

0.24.0

  • Added source-led Agent Knowledge for hierarchical grid selection, indexed relationships, expansion, active-cell focus, row selection, header actions, and virtualization boundaries.

0.18.0

  • Added ColumnHeader.onAction with equivalent enabled pointer and active-cell Enter activation.
  • Relocate active state to a collapsed ancestor's tree-column cell when a controlled or uncontrolled collapse hides the active descendant.

0.2.0

  • Added Direction.Provider and dir support to mirror TreeGrid horizontal cell navigation and expand/collapse arrow behavior in RTL.

0.1.0

  • Initial Atom release.