React Tree Table
A plain data table flattens a hierarchy into a list; a tree view keeps the hierarchy but drops the columns. This keeps both — the right shape for anything that is a tree and has numbers on every row: a bundle breakdown, a budget, a file system, an org chart.
| Module | Size | Gzip | % of bundle |
|---|---|---|---|
vendor | 412 KB | 138 KB | 66% |
react-dom | 130 KB | 42 KB | 21% |
motion | 96 KB | 33 KB | 15% |
charting | 118 KB | 40 KB | 19% |
lucide-react | 68 KB | 23 KB | 11% |
app | 214 KB | 71 KB | 34% |
docs/* | 148 KB | 49 KB | 24% |
components/site | 66 KB | 22 KB | 11% |
Expand a group to see its children — the hierarchy of a tree with the aligned columns of a table.
Installation
Props
| Prop | Type | Description |
|---|---|---|
| nodes | TreeNode<T>[] | { id, data, children? } |
| columns | TreeColumn<T>[] | { key, header, render, align?, tree? } |
| defaultExpandedDepth | number | Expand down to this depth initially |
One column carries the tree
Mark a column tree: true and it renders the indentation and the expand/collapse control; every other column is a plain aligned cell. That separation is what lets the same component show a bundle's module tree with right-aligned size and gzip columns, or a budget's line items with a percentage — the hierarchy lives in one column, the metrics in the rest, and they never fight for space.
Rows are flattened on each render from the set of expanded nodes, so state is a single Set of ids rather than a flag per node — cheap, and impossible to get out of sync. Generic over your row type T, with a render per column, so it stays a table of your data, not a fixed schema. Parent rows read slightly heavier than leaves, so the shape of the tree is legible even before you expand anything.
New components every week
Get the week's new Kelvin UI components and templates in one short email. No spam, unsubscribe anytime.