جدول البيانات: الصفوف الشجرية
هذه الصفحة غير مترجمة بعد، وهي معروضة بالإنجليزية.
The data table shows nested rows when you pass getSubRows, a function that returns a row’s children. Rows with children get an expand toggle in their first cell, and each level is indented. Pass expanded with onExpandedChange to control which rows are open.
Engineering | Yuki Tanaka | 42 |
Product | Omar Haddad | 15 |
Customer care | Hana Kim | 12 |
Every row is collapsed.
import { useState } from "react";
import { DataTable, type DataTableColumnDef, type DataTableExpandedState } from "slotsmith/data-table";
type Unit = { id: string; name: string; lead: string; headcount: number; units?: Unit[] };
const company: Unit[] = [
{
id: "eng",
name: "Engineering",
lead: "Yuki Tanaka",
headcount: 42,
units: [
{
id: "eng-platform",
name: "Platform",
lead: "Lena Park",
headcount: 18,
units: [
{ id: "eng-platform-infra", name: "Infrastructure", lead: "Diego Alvarez", headcount: 10 },
{ id: "eng-platform-tools", name: "Developer tools", lead: "Sofia Reyes", headcount: 8 },
],
},
{ id: "eng-payments", name: "Payments", lead: "Chloe Martin", headcount: 24 },
],
},
{
id: "product",
name: "Product",
lead: "Omar Haddad",
headcount: 15,
units: [
{ id: "product-design", name: "Design", lead: "Priya Nair", headcount: 9 },
{ id: "product-research", name: "Research", lead: "Amir Nasser", headcount: 6 },
],
},
{ id: "care", name: "Customer care", lead: "Hana Kim", headcount: 12 },
];
const columns: DataTableColumnDef<Unit>[] = [
// The first column holds the expand toggle and is indented by depth.
{ accessorKey: "name", header: "Unit" },
{ accessorKey: "lead", header: "Lead" },
{ accessorKey: "headcount", header: "People", meta: { align: "end" } },
];
export default function TreeRows() {
const [expanded, setExpanded] = useState<DataTableExpandedState>({});
const open = expanded === true ? "all" : Object.keys(expanded).filter((id) => expanded[id]);
return (
<>
<DataTable
data={company}
columns={columns}
getRowId={(unit) => unit.id}
// Each row's children: rows with any become expandable.
getSubRows={(unit) => unit.units}
expanded={expanded}
onExpandedChange={setExpanded}
enablePagination={false}
/>
<p>{open.length === 0 ? "Every row is collapsed." : `Expanded: ${open === "all" ? "all" : open.join(", ")}`}</p>
</>
);
}Open Engineering, then Platform, to see two levels of sub-rows. The text under the table lists the expanded rows by id.
Sub-rows
getSubRows receives each row and returns its children, or undefined for a leaf. The children use the same columns as their parent. Give every row, at every level, an id with getRowId, so the expanded state, the selection and a row reorder follow the row and not its position.
For children that load later, getRowCanExpand decides which rows show a toggle before their children arrive; fetch the children when the row expands and put them in data.
Expanded state
expandedandonExpandedChangecontrol it, as the demo does. The state is{ [rowId]: true }for the open rows, ortruefor every row.defaultExpandedsets a starting state the table keeps itself, such as{ eng: true }ortrueto open everything.paginateExpandedRowscounts sub-rows towards the page size. By default only top-level rows count, so a page keeps its parents’ children with it.
The parts
The toggle is the ExpandToggle slot: a <button> with aria-expanded, named by the expandRow or collapseRow label. It receives expanded, depth and onToggle, and a click on it does not run onRowClick. A row with no children gets a spacer in its place, so the names line up. The built-in toggle also sets an empty data-expanded on itself while open, which its stylesheet uses to turn the chevron; a toggle of your own gets expanded and sets whatever it needs.
Each Row carries data-depth (0 for top-level rows) and, when it can expand, data-expanded ("true" or "false"), so a stylesheet can mark the levels.