Row Grouping

Organize rows into expandable hierarchies — load children upfront or on demand.

  1. Mark the expandable column

    Set expandable: true on the column that shows the hierarchy label (where the expand control appears).
    TypeScript
    {
    accessor: "organization",
    label: "Organization",
    width: 200,
    expandable: true,
    }
  2. Shape nested data

    Nest child arrays under property names you will list in rowGrouping. Child rows share the same columns — for different columns per level, see Nested Tables.
    TypeScript
    {
    id: "company-1",
    organization: "TechSolutions Inc.",
    divisions: [
    {
    id: "div-100",
    organization: "Engineering",
    departments: [
    { id: "dept-1", organization: "Frontend" },
    { id: "dept-2", organization: "Backend" },
    ],
    },
    ],
    }
  3. Set rowGrouping

    Pass rowGrouping in depth order, plus getRowId so expansion stays stable across sort and updates.
    React TSX
    <SimpleTable
    columns={columns}
    rows={rows}
    rowGrouping={["divisions", "departments"]}
    getRowId={({ row }) => String(row.id)}
    />

Patterns

Start expanded

Set expandAll so grouped rows open on first load.

React TSX
<SimpleTable
columns={columns}
rows={rows}
rowGrouping={["divisions", "departments"]}
getRowId={({ row }) => String(row.id)}
expandAll
/>

Sticky parent rows

Set enableStickyParents so parents stick while you scroll their children. Beta — defaults to off.

React TSX
<SimpleTable
columns={columns}
rows={rows}
rowGrouping={["divisions", "departments"]}
getRowId={({ row }) => String(row.id)}
enableStickyParents
/>

Lazy-load children

Use onRowGroupExpand to fetch children on expand. Helpers setLoading, setError, and setEmpty drive row states; rowIndexPath locates the nested row to update.

React TSX
<SimpleTable
columns={columns}
rows={rows}
rowGrouping={["stores", "products"]}
getRowId={({ row }) => String(row.id)}
onRowGroupExpand={async ({ row, isExpanded, groupingKey, setLoading, setError, setEmpty, rowIndexPath }) => {
if (!isExpanded) return;
setLoading(true);
try {
const children = await fetchChildren(row.id, groupingKey);
setLoading(false);
if (children.length === 0) {
setEmpty(true, "No data");
return;
}
// update rows using rowIndexPath / groupingKey
} catch (error) {
setLoading(false);
setError(error.message);
}
}}
/>

Programmatic expand / collapse

Control expansion from the table API: expandAll, collapseAll, expandDepth, setExpandedDepths, toggleDepth.

React TSX
tableRef.current?.expandAll();
tableRef.current?.collapseAll();
tableRef.current?.expandDepth(0);
tableRef.current?.setExpandedDepths(new Set([0, 1]));
tableRef.current?.toggleDepth(0);

Example

Control Expansion:

Dynamic loading example

Children load when a parent expands (regions → stores → products).

Props

Row Grouping Configuration

PropertyRequiredDescriptionExample
ColumnDef.expandable
boolean
Optional
Shows the expand/collapse control on this column for hierarchical rows.
rowGrouping
string[]
Optional
Nested array property names that define hierarchy levels, in depth order.
expandAll
boolean
Optional
When true, grouped rows start expanded.
getRowId
(props: { row: Row }) => string | number | null | undefined
Optional
Stable row id so expansion survives sort and data updates.
Optional
Fires on expand/collapse. Includes setLoading, setError, setEmpty, and rowIndexPath for lazy loading.
canExpandRowGroup
(row: Row) => boolean
Optional
Return false to disable expand for a specific row.
enableStickyParents
boolean
Optional
Beta: sticky parent rows while scrolling through children. Default false.
loadingStateRenderer
string | ReactNode
Optional
Custom content for loading rows (from setLoading). Default skeleton if omitted.
errorStateRenderer
string | ReactNode
Optional
Custom content for error rows (from setError).
emptyStateRenderer
string | ReactNode
Optional
Custom content for empty child rows (from setEmpty).