Org charts, file systems, BOMs, ledger structures—real-world data is rarely flat. Tree-data tables let users expand and collapse rows in place to drill down without losing context.
This tutorial covers tree-data patterns in Vue 3: parent/child rendering, lazy loading children, and expand-all / collapse-all controls. We compare PrimeVue TreeTable, Element Plus, Naive UI, and Simple Table for Vue.
Note: PrimeVue and Element Plus split tree data into separate components. Simple Table for Vue uses the same SimpleTable component for flat and hierarchical data.
Why it matters
Drill-down without losing context
Users see parent and children in the same surface; no modal or detail-page round-trips.
Compact wide hierarchies
Collapse low-level children; expand specific branches users care about.
Reusable for many domains
Folders, regions, org charts, and chart-of-accounts all share the pattern.
Combinable with sort/filter
Filter the leaves; the right ancestors stay visible to preserve context.
Vue library comparison
| Library | Support | Notes |
|---|---|---|
| Simple Table for Vue | Built-in (MIT) | Hierarchical rows with built-in expand/collapse and chevron renderer. |
| PrimeVue TreeTable | Built-in | <TreeTable> separate from <DataTable>; different API surface. |
| Element Plus el-table | Built-in | row-key + tree-props + lazy + load. |
| Vuetify v-data-table | Manual | No native tree data—pre-flatten and render with row templates. |
| Naive UI n-data-table | Built-in | children key in row + indent rendering. |
Implementation: Simple Table for Vue
Provide hierarchical rows with depth per the docs. Simple Table renders chevrons and handles expand/collapse state for you.
Common pitfalls
Performance on deep trees
Problem: Expanding a node with 10k descendants stalls the UI.
Solution: Lazy-load children on expand, and rely on built-in virtualization.
Filtering hides ancestors
Problem: Searching matches a leaf, but the tree breaks because parents are filtered out.
Solution: Filter while preserving ancestor rows. Simple Table supports this with includeAncestors filter mode.
Expanded state lost on refresh
Problem: Polling refresh closes every expanded branch.
Solution: Hold isExpanded by stable rowId in a ref / store and reapply after refetch.
Indent ambiguity
Problem: Multiple columns indent independently; users can't tell where children belong.
Solution: Indent only the tree column (usually the first). Simple Table does this automatically with expandable: true.
Frequently asked questions
- Does Simple Table for Vue have a separate TreeTable?
- No—the same SimpleTable component handles flat and hierarchical data. Provide depth and expansion information per the nested tables docs to render a tree.
- Can I use tree data with column pinning and grouping?
- Yes. Tree data, pinning, virtualization, sorting, and filtering all combine in the same component.
- How do I implement a 'select all descendants' checkbox?
- Use selectableCells="row" and listen for selection events. When the user toggles a parent, propagate to all descendants in your handler.
Wrap-up
Tree data in Vue 3 is straightforward with Simple Table—provide hierarchy on each row and Simple Table handles the rest. PrimeVue and Element Plus support it but with separate components or props; Vuetify requires DIY.
If you need hierarchical data alongside virtualization and pinning, Simple Table for Vue is the focused MIT pick.