
Multi-level DataGrid tree mode for an HR org chart: recursive subRows at arbitrary depth, DataGridTableRowExpand indentation, org size and open roles rolled up each reporting line, tree-cascading row selection with a corrected tri-state checkbox, sticky header, depth control and a bulk selection bar.
A reporting-hierarchy explorer for people teams and leaders who need to walk an org from the chief executive down to an individual contributor, and see span of control, open roles and who needs attention roll up every reporting line.
Frame shell with company and snapshot line, four org KPIs (Headcount, Layers, Avg span, Open roles), and an Export actionDataGrid in tree mode: recursive getSubRows with no depth cap and DataGridTableRowExpand supplying per-level indentation from row.depthTreeRowSelect that fixes the primitive checkbox, which is not tri-state on a tree in either direction1, 2, 3, All) that expands the whole tree to a chosen levelbuildOrgRows: org size, direct reports, open roles, layers below, and people needing attentionDataGridTable footer built one cell per visible column so it tracks column toggles@tanstack/react-table for recursive nested rows, controlled expansion and selection state, stable row ids, column visibility, and flattened row renderingsonner for preview-safe action feedbackORG_TREE with your real reporting lines; nodes are self-recursive, so depth is whatever your org has.buildOrgRows.getRowId returns them flat, so expansion and selection stay predictable at any depth.getRootExpandedState opens the root and nothing else; swap it for getLevelExpandedState(rows, n) for a uniform depth.TREE_INDENT in columns.tsx and the leaf spacer widths together; they are a pair, and the spacer tracks the density switch because the primitive's toggle does.Export to your HRIS.DataGridTableRowSelect on a tree; it renders a manager solid-checked after one report is unchecked, and blank when every report was checked individually. Derive from getIsAllSubRowsSelected().getSelectedRowModel().rows; that model is nested and drops a selected report whose manager is unselected. Use flatRows.headerSticky without bounding the scroll area; the viewport grows to content, so the header never sticks.meta.expandedContent anywhere in a tree block; it shares row.getIsExpanded() with the tree, so every expanded manager grows a detail row inside their own subtree, and hiding the column does not switch it off.table.toggleAllRowsExpanded(); it writes the boolean true, which makes every row including leaves report as expanded.getSubRows on a node kind; return row.children at every level or the tree silently flattens.Back each person with a stable id, name, title, level, department, location, employment status, hire date, and the open roles attached directly to them. For server-backed data, fetch the flat person list with a manager id and build the child arrays on the client or server before passing the tree into TanStack Table. Sum counts upward and take the deepest branch for layers, so a manager's row always describes their whole line. If filtering becomes server-backed, return whole manager paths rather than bare people, and preserve the same controlled expanded and selection state shape.
Use this block when the user asks for an org chart, a reporting hierarchy, a people tree, or any parent-child table of humans where a manager summarises their reports. This is the people tree in the grouping family; data-grid-grouping-1 is a flat headerless grouped list, data-grid-grouping-2 a one-level region rollup, data-grid-grouping-3 a grouped cohort heatmap, and data-grid-grouping-4 a bill-of-materials tree keyed on parts rather than people. Preserve the recursive getSubRows, the DataGridTableRowExpand indentation with its density-aware leaf spacer, the block-level TreeRowSelect, the flat-row selection count, the bounded scroll area under the sticky header, the single-pass buildOrgRows derivation, the ancestor-preserving filter, the root-only default expansion, and the semantic Badge usage unless the brief explicitly changes the hierarchy or the measures.