Tree data
Nest rows into an expandable hierarchy with the treeData prop.
Open the live example: Tree data (hierarchy) (Sorting & Grouping)
Transcript
Tree data is one prop. Point treeData at the parent field and name the tree column, and flat rows become a hierarchy.
Click an expander to open a branch. Children indent under their parent and keep every column.
Expand all and Collapse all walk the whole tree through the grid API.
Nested objects work too: flatten them once with flattenTreeData, and the same prop takes it from there.
Tree rows are real data rows. They keep their own cells, formatting, editing and selection, and only gain an expander plus indentation in the tree column. That is the difference from row grouping, where the parent is a synthetic full-width banner standing in for its children.
Flat data (parent id)
The model nests by parent id, so data that already carries one needs no preparation:
The examples on this page run against these rows:
<script lang="ts">
import { SvGrid, type GridColumns } from '@svgrid/grid'
type Person = {
id: number
name: string
email: string
department: string
age: number
salary: number
city: string
startDate: string
active: boolean
}
const people: Person[] = [
{ id: 1, name: 'Ada Lovelace', email: '[email protected]', department: 'Engineering', age: 36, salary: 142000, city: 'London', startDate: '2021-03-01', active: true },
{ id: 2, name: 'Grace Hopper', email: '[email protected]', department: 'Engineering', age: 45, salary: 168000, city: 'New York', startDate: '2019-07-15', active: true },
{ id: 3, name: 'Linus Torvalds', email: '[email protected]', department: 'Platform', age: 54, salary: 155000, city: 'Portland', startDate: '2020-01-20', active: false },
{ id: 4, name: 'Radia Perlman', email: '[email protected]', department: 'Networking', age: 49, salary: 161000, city: 'Seattle', startDate: '2022-09-05', active: true },
{ id: 5, name: 'Barbara Liskov', email: '[email protected]', department: 'Platform', age: 52, salary: 172000, city: 'Boston', startDate: '2018-11-11', active: true },
]
const columns: GridColumns<Person> = [
{ field: 'name', header: 'Name', width: 200 },
{ field: 'department', header: 'Department', width: 150 },
{ field: 'city', header: 'City', width: 140 },
{ field: 'age', header: 'Age', width: 90 },
{ field: 'salary', header: 'Salary', width: 130, format: { type: 'currency', currency: 'USD' } },
]
</script>
<script lang="ts">
import { SvGrid } from '@svgrid/grid'
const people = [
{ id: 1, managerId: null, name: 'Ada', title: 'CEO' },
{ id: 2, managerId: 1, name: 'Grace', title: 'VP Engineering' },
{ id: 3, managerId: 2, name: 'Alan', title: 'Principal Engineer' },
]
</script>
<SvGrid
data={people}
{columns}
treeData={{ parentField: 'managerId', column: 'name' }}
/>
| Option | Meaning |
|---|---|
parentField |
Field holding each row's parent id. Required. |
idField |
Field holding the row's own id. Defaults to 'id'. |
column |
Column that carries the expander + indent. Defaults to the first visible column. |
indentPx |
Indent per depth level, in px. Default 12. |
Nested data (children arrays)
The grid only builds rows for the objects in data, so children nested inside
a parent are never rows. Flatten them first:
<script lang="ts">
import { SvGrid, flattenTreeData } from '@svgrid/grid'
const tree = [
{ id: 1, name: 'src', children: [
{ id: 2, name: 'components', children: [{ id: 3, name: 'Grid.svelte' }] },
] },
]
// Stamps `__parentId` on every child and returns one flat list, children
// directly after their parent.
const rows = flattenTreeData(tree, { childrenField: 'children' })
</script>
<SvGrid data={rows} {columns} treeData={{ parentField: '__parentId', column: 'name' }} />
flattenTreeData takes childrenField, plus optional idField (default
'id') and parentField (default '__parentId') if you want a different link
field.
Accessibility
Turning on treeData puts the grid in the treegrid role. Every row gets
aria-level, and expandable rows get aria-expanded. Keyboard:
| Key | Action |
|---|---|
| → | Expand the focused row |
| ← | Collapse the focused row |
| Enter / click | Toggle via the expander button |
Rows without children render a spacer where the chevron would be, so values stay aligned with their expandable siblings.
Edge cases
- Missing parent. A row whose
parentFieldpoints at an id that is not in the data becomes a root rather than disappearing. Losing rows silently is worse than a shallower tree - this matters when a filter removes a parent but keeps a child. - Self-parenting. A row that names itself as its parent is treated as a root.
- Cycles. A loop in the parent chain is detected and stops the walk instead of recursing forever.
- Grouping.
treeDatareplaces row grouping - a row cannot be both a hierarchy node and bucketed under a group banner.
Server-side trees
For hierarchies too large to send at once, load children on demand with
serverGroup and ServerDataSource instead - see
Server-side data. The two share the same treegrid
keyboard and ARIA contract.
More examples
Project WBS tree
Phase → task → subtask with % complete that rolls up via effort-weighted average when you edit any leaf.
Open the live example: Project WBS tree (Tree & Hierarchy)
Bill of Materials
Bicycle BOM, 4 levels deep. Edit any leaf part's qty or unit cost; subtotals roll up through the assembly chain to the grand total.
Open the live example: Bill of Materials (Tree & Hierarchy)
See also
- Demo #426 Tree data
- Grouping & aggregation - the row-bucketing shape
- Master / detail - a rich panel under a row, rather than child rows
Live examples
- Tree data (hierarchy) - treeData nests rows by parent id into an expandable hierarchy. Tree rows stay real data rows - own cells, formatting, editing - and just gain an expander plus indent. Takes flat parent-id data directly, or nested children arrays via flattenTreeData. Full treegrid a11y with arrow-key expand.
- Project WBS tree - Phase → task → subtask with % complete that rolls up via effort-weighted average when you edit any leaf.
- Bill of Materials - Bicycle BOM, 4 levels deep. Edit any leaf part's qty or unit cost; subtotals roll up through the assembly chain to the grand total.
Related articles
- SvGrid UI Components Tips and Tricks: Svelte 5 Buttons, Inputs, Tree, Forms - Practical tips for the SvGrid UI component kit - SvButton states, a Cmd+K command palette, a virtualized searchable tree, schema-driven forms, a parsing date/time field, and the shared field contract - each with a code snippet.
- Inside SvGrid: Grouping, Trees, and Master-Detail - Three different ways to show hierarchy in a data grid, unified under one expansion model in SvGrid - the design decision and how each feature actually works.
- Displaying Tree Data and Hierarchies in SvGrid - Render parent-child hierarchies - org charts, file trees, category taxonomies - in SvGrid with expandable rows, size rollups, and lazy child loading.