EXEPERTAI LAB

Research alpha

Time Machine
EXEPERTAI LAB
GALLERY / COLLECTION
← Browse Astryx gallery
Table·hook·@astryxdesign/core

useTableTreeState

State management companion for useTableTreeData. Owns the expanded set (controlled or uncontrolled) and flattens nested data into the visible row array; collapsed subtrees are unmounted, not hidden, so the table body contains exactly the visible rows. Returns expandAll/collapseAll helpers, the aggregate isAllExpanded state (true/false/indeterminate) for a header expand-all control, and a ready-to-use config for the tree plugin. Note: because collapsed rows unmount, cell-local React state inside collapsed subtrees is lost on collapse; lift state that must survive.

Open in Playground @astryxdesign/core/Table

Signature

Call shape
useTableTreeState()

Showcases and examples

1 documented example

useTableTreeData: Tree Table

A file-tree table built from nested data. useTableTreeState flattens the tree into the visible rows and owns the expanded set; useTableTreeData draws the per-level indent and the expand/collapse chevron in the tree column. The two hooks are designed to work together, so this one example covers both. hasExpandAllControl adds the expand-all/collapse-all toggle to the tree column header. Collapsed branches are unmounted, not hidden.

Preview loads on approachPreview loads on approach
Exact source · table-tree-table
// Copyright (c) Meta Platforms, Inc. and affiliates.

'use client';

import {
  Table,
  useTableTreeData,
  useTableTreeState,
  proportional,
  pixel,
} from '@astryxdesign/core/Table';

interface FileNode extends Record<string, unknown> {
  id: string;
  name: string;
  kind: 'folder' | 'file';
  size: string;
  children?: FileNode[];
}

const fileTree: FileNode[] = [
  {
    id: 'src',
    name: 'src',
    kind: 'folder',
    size: '',
    children: [
      {
        id: 'src/components',
        name: 'components',
        kind: 'folder',
        size: '',
        children: [
          {
            id: 'src/components/Button.tsx',
            name: 'Button.tsx',
            kind: 'file',
            size: '4.2 KB',
          },
          {
            id: 'src/components/Table.tsx',
            name: 'Table.tsx',
            kind: 'file',
            size: '12.8 KB',
          },
        ],
      },
      {id: 'src/index.ts', name: 'index.ts', kind: 'file', size: '0.4 KB'},
    ],
  },
  {id: 'package.json', name: 'package.json', kind: 'file', size: '1.8 KB'},
];

const columns = [
  {key: 'name', header: 'Name', width: proportional(2)},
  {key: 'kind', header: 'Kind', width: pixel(90)},
  {key: 'size', header: 'Size', width: pixel(90)},
];

export default function TableTreeTable() {
  // useTableTreeState owns the expanded set and flattens the nested data into
  // the visible rows; useTableTreeData draws the indent + expander in the tree
  // column. hasExpandAllControl adds the expand-all toggle to the header.
  const {visibleData, treeConfig} = useTableTreeState<FileNode>({
    data: fileTree,
    idKey: 'id',
    defaultExpandedIds: ['src'],
  });

  const tree = useTableTreeData({...treeConfig, hasExpandAllControl: true});

  return (
    <Table
      data={visibleData}
      columns={columns}
      idKey="id"
      hasHover
      plugins={{tree}}
    />
  );
}

Usage

State management companion for useTableTreeData. Owns the expanded set (controlled or uncontrolled) and flattens nested data into the visible row array; collapsed subtrees are unmounted, not hidden, so the table body contains exactly the visible rows. Returns expandAll/collapseAll helpers, the aggregate isAllExpanded state (true/false/indeterminate) for a header expand-all control, and a ready-to-use config for the tree plugin. Note: because collapsed rows unmount, cell-local React state inside collapsed subtrees is lost on collapse; lift state that must survive.

Typed props

PropType and behavior
dataT[] · required
Nested data: rows may carry child rows under childrenKey. Flat data (no children anywhere) makes the plugin a no-op, so it can be adopted before the data becomes hierarchical.
idKey(keyof T & string) | ((item: T) => string | number) · required
Row ID accessor: property name or function returning a unique id.
childrenKeystring · default 'children'
Property holding each row's children array.
defaultExpandedIdsIterable<string>
Initial expanded row ids for uncontrolled mode. Ignored when expandedIds is provided.
expandedIdsReadonlySet<string>
Controlled set of expanded row ids. Pair with onExpandedIdsChange.
onExpandedIdsChange(ids: ReadonlySet<string>) => void
Called with the next expanded set whenever expansion changes (both modes). In lazy-loading setups, trigger the children fetch here.
isItemExpandable(item: T) => boolean
Should this row show an expander? Overrides the default non-empty-children check; use for lazy loading, where a row is expandable before its children have been fetched.
sortSiblings(siblings: T[]) => T[]
Sort each sibling group independently during flattening; children always stay directly under their parent. Pass applySort from useTableSortableState to compose with column sorting.
indent'sm' | 'md' | 'lg' · default 'md'
Indent step per level (spacing-3 / spacing-4 / spacing-6), forwarded to useTableTreeData.
treeColumnKeystring
Column that carries the indent + expander, forwarded to useTableTreeData. Defaults to the first column.