
Multi-level DataGrid tree mode for a bill of materials: recursive subRows at arbitrary depth, DataGridTableRowExpand depth indentation, quantity multiplied down the tree, cost and lead time rolled up, supply risk badges, a depth level control and a grand-total footer.
A bill of materials cost explorer for hardware engineering and sourcing teams that need to expand a product into systems, assemblies, sub-assemblies and purchased parts, and see where cost, lead time and supply risk actually sit.
Frame shell with title, product and revision line, three build KPIs (Build cost, Critical path, At risk), and an Export actionDataGrid in true tree mode: recursive getSubRows with no depth cap, and the DataGridTableRowExpand primitive supplying per-level indentation from row.depthCollapse, 1, 2, All) that expands the whole tree to a chosen level and reports -1 once a row is toggled by handBOM_NODE_ICONS) keyed by node id, falling back to BOM_KIND_ICONS, so a long tree does not repeat one glyphBadge as the column, so the option matches the cell it selectsbuildBomRows: effective quantity multiplied down the tree, extended cost and part count summed upward, longest lead time as the critical path, worst descendant supply statusDataGridTable grand-total footer built one cell per visible column so it tracks column togglesDisplay popover with density, a part detail line, and column toggles for number, unit cost, lead time, and supply@tanstack/react-table for recursive nested rows, controlled expansion state, stable row ids, column visibility, and flattened row renderingsonner for preview-safe action feedbackBOM_TREE with your real product structure; nodes are self-recursive, so depth is whatever your data has.qty, per-unit unitCost, and leadTimeDays in the data. Every rolled-up figure derives in buildBomRows.getRowId returns them flat, so expansion state stays predictable at any depth.getFirstPathExpandedState opens the first branch at every level on first paint; swap it for getLevelExpandedState(rows, n) if you want a uniform depth instead.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 PLM, ERP, or sourcing flow.ps-8 indent; DataGridTableRowExpand is what makes depth beyond one level work.getSubRows on a node kind; return row.children at every level or the tree silently flattens.secondary badge in the FrameHeader; it sits on the Frame gutter tint and reads as plain text.Back each node with a stable id, part number, name, kind, per-parent quantity, and, for purchased parts, a unit cost, lead time, supply status and supplier. For server-backed data, fetch the flat node list with a parent id and build the child arrays on the client or server before passing the tree into TanStack Table. Roll quantity down the tree and cost up it, so a sub-assembly used twice counts its parts twice. If filtering becomes server-backed, return whole ancestor paths rather than bare leaves, and preserve the same controlled expanded state and flat row id shape.
Use this block when the user asks for a data grid whose hierarchy is deeper than one grouping level: a bill of materials, product structure, chart of accounts, cost rollup, folder tree, or any parent-child table where parent values must derive from descendants. This is the tree-mode sibling in the grouping family; data-grid-grouping-1 is a flat headerless grouped list, data-grid-grouping-2 a one-level region rollup with a grand total, and data-grid-grouping-3 a grouped cohort heatmap. Preserve the recursive getSubRows, the DataGridTableRowExpand indentation with its leaf spacer, the single-pass buildBomRows derivation, the ancestor-preserving filter, the depth level control, the share-of-build donut, the per-node icon map, the derived grand-total footer, the portable IconPlaceholder mappings, and the semantic Badge usage unless the brief explicitly changes the hierarchy or the measures.