Interactive table generation JavaScript library with sorting, filtering, editing, formatting, and extensive customization capabilities
—
Hierarchical data tree functionality for displaying nested data structures with expandable/collapsible parent-child relationships and custom tree controls.
Configure hierarchical data display with parent-child relationships and tree controls.
interface DataTreeOptions {
dataTree?: boolean;
dataTreeFilter?: boolean;
dataTreeSort?: boolean;
dataTreeElementColumn?: string | false;
dataTreeBranchElement?: boolean | string | HTMLElement;
dataTreeChildIndent?: number;
dataTreeChildField?: string;
dataTreeCollapseElement?: string | HTMLElement | false;
dataTreeExpandElement?: string | HTMLElement | false;
dataTreeStartExpanded?: boolean | Function | boolean[];
dataTreeChildColumnCalcs?: boolean;
dataTreeSelectPropagate?: boolean;
}Tree-specific methods added to RowComponent for managing hierarchical relationships.
// Added to RowComponent by DataTree module
/**
* Collapse this tree row and hide its children
*/
treeCollapse(): void;
/**
* Expand this tree row and show its children
*/
treeExpand(): void;
/**
* Toggle expansion state of this tree row
*/
treeToggle(): void;
/**
* Get the parent row in the tree hierarchy
* @returns Parent RowComponent or false if top-level
*/
getTreeParent(): RowComponent | false;
/**
* Get all direct child rows in the tree
* @returns Array of child RowComponent objects
*/
getTreeChildren(): RowComponent[];
/**
* Add a new child row to this tree row
* @param data - Data for the new child row
* @param pos - Position to insert (true for top, false for bottom)
* @param index - Index to insert before
* @returns Promise resolving to new RowComponent
*/
addTreeChild(data: any, pos?: boolean, index?: any): Promise<RowComponent>;
/**
* Check if this tree row is currently expanded
* @returns True if expanded, false if collapsed
*/
isTreeExpanded(): boolean;Usage Examples:
import { Tabulator } from "tabulator-tables";
// Basic tree structure
const treeData = [
{
name: "Engineering",
employees: 15,
_children: [
{
name: "Frontend Team",
employees: 8,
_children: [
{ name: "Alice Johnson", role: "Senior Developer", employees: 1 },
{ name: "Bob Smith", role: "Developer", employees: 1 },
{ name: "Carol White", role: "UI/UX Designer", employees: 1 }
]
},
{
name: "Backend Team",
employees: 7,
_children: [
{ name: "David Brown", role: "Tech Lead", employees: 1 },
{ name: "Eve Davis", role: "Senior Developer", employees: 1 },
{ name: "Frank Wilson", role: "DevOps Engineer", employees: 1 }
]
}
]
},
{
name: "Sales",
employees: 12,
_children: [
{ name: "Grace Miller", role: "Sales Manager", employees: 1 },
{ name: "Henry Taylor", role: "Account Executive", employees: 1 },
{ name: "Ivy Anderson", role: "Sales Rep", employees: 1 }
]
}
];
// Table with tree functionality
const table = new Tabulator("#tree-table", {
data: treeData,
columns: [
{
title: "Name",
field: "name",
width: 300,
formatter: "plaintext"
},
{
title: "Role/Department",
field: "role",
formatter: function(cell, formatterParams) {
return cell.getValue() || cell.getRow().getData().name;
}
},
{
title: "Employees",
field: "employees",
width: 100,
align: "right"
}
],
dataTree: true,
dataTreeStartExpanded: true,
dataTreeChildField: "_children",
dataTreeChildIndent: 15,
dataTreeElementColumn: "name"
});
// Programmatic tree operations
const firstRow = table.getRows()[0];
// Collapse a tree row
firstRow.treeCollapse();
// Expand a tree row
firstRow.treeExpand();
// Toggle expansion state
firstRow.treeToggle();
// Check expansion state
if (firstRow.isTreeExpanded()) {
console.log("Row is expanded");
}
// Get tree relationships
const children = firstRow.getTreeChildren();
console.log(`This row has ${children.length} children`);
children.forEach(child => {
const parent = child.getTreeParent();
console.log(`Child row parent: ${parent ? parent.getData().name : 'none'}`);
});
// Add new child
firstRow.addTreeChild({
name: "Quality Assurance Team",
employees: 5,
_children: [
{ name: "Jack Lee", role: "QA Lead", employees: 1 },
{ name: "Kate Green", role: "QA Engineer", employees: 1 }
]
});Specify which field contains child data in your data structure.
const table = new Tabulator("#table", {
dataTree: true,
dataTreeChildField: "_children", // Default field name
// ... other options
});
// Alternative field names
dataTreeChildField: "children" // Use "children" field
dataTreeChildField: "subItems" // Use "subItems" field
dataTreeChildField: "nested" // Use "nested" fieldCustomize tree appearance with custom elements and indentation.
const table = new Tabulator("#table", {
dataTree: true,
dataTreeChildIndent: 20, // Indent child rows by 20px
dataTreeBranchElement: true, // Show default branch lines
dataTreeElementColumn: "name", // Column to show tree controls in
// Custom collapse/expand buttons
dataTreeCollapseElement: "<span>▼</span>",
dataTreeExpandElement: "<span>▶</span>",
// Custom branch element
dataTreeBranchElement: "<div class='custom-branch'></div>"
});Control which tree rows start expanded or collapsed.
// All rows start expanded
const table = new Tabulator("#table", {
dataTree: true,
dataTreeStartExpanded: true
});
// All rows start collapsed
const table2 = new Tabulator("#table2", {
dataTree: true,
dataTreeStartExpanded: false
});
// Conditional expansion using function
const table3 = new Tabulator("#table3", {
dataTree: true,
dataTreeStartExpanded: function(row, level) {
// Expand top-level rows, collapse deeper levels
return level < 2;
}
});
// Specific expansion levels using array
const table4 = new Tabulator("#table4", {
dataTree: true,
dataTreeStartExpanded: [true, true, false] // Expand levels 0,1 but not 2+
});Configure how child rows are handled in filtering and sorting operations.
const table = new Tabulator("#table", {
dataTree: true,
dataTreeFilter: true, // Include child rows in filtering
dataTreeSort: true, // Include child rows in sorting
// Child row calculations
dataTreeChildColumnCalcs: true, // Include visible children in calculations
// Selection propagation
dataTreeSelectPropagate: true, // Selecting parent selects children
});Dynamically modify tree structure after table creation.
// Add children to existing rows
const parentRow = table.getRow(1);
await parentRow.addTreeChild({
name: "New Team Member",
role: "Junior Developer",
employees: 1
});
// Traverse tree programmatically
function traverseTree(row, level = 0) {
const indent = " ".repeat(level);
console.log(`${indent}${row.getData().name}`);
const children = row.getTreeChildren();
children.forEach(child => {
traverseTree(child, level + 1);
});
}
// Traverse all top-level rows
table.getRows().forEach(row => {
if (!row.getTreeParent()) {
traverseTree(row);
}
});
// Batch tree operations
const engineeringTeam = table.getRows().find(row =>
row.getData().name === "Engineering"
);
if (engineeringTeam) {
// Collapse all children
engineeringTeam.getTreeChildren().forEach(child => {
child.treeCollapse();
});
// Then expand the parent
engineeringTeam.treeExpand();
}Handle tree-specific events for user interactions.
// Tree expansion/collapse events
table.on("dataTreeRowExpanded", function(row, level) {
console.log(`Row expanded: ${row.getData().name} at level ${level}`);
});
table.on("dataTreeRowCollapsed", function(row, level) {
console.log(`Row collapsed: ${row.getData().name} at level ${level}`);
});
// Custom tree button handling
table.on("rowClick", function(e, row) {
// Check if click was on tree control
if (e.target.closest('.tabulator-data-tree-control')) {
row.treeToggle();
}
});Standard hierarchical data with child arrays.
const nestedData = [
{
id: 1,
name: "Parent 1",
_children: [
{
id: 2,
name: "Child 1.1",
_children: [
{ id: 3, name: "Grandchild 1.1.1" },
{ id: 4, name: "Grandchild 1.1.2" }
]
},
{ id: 5, name: "Child 1.2" }
]
}
];Transform flat data with parent references into tree structure.
const flatData = [
{ id: 1, name: "Parent 1", parentId: null },
{ id: 2, name: "Child 1.1", parentId: 1 },
{ id: 3, name: "Child 1.2", parentId: 1 },
{ id: 4, name: "Grandchild 1.1.1", parentId: 2 }
];
// Transform to nested structure
function buildTree(flatData) {
const tree = [];
const lookup = {};
// Create lookup map
flatData.forEach(item => {
lookup[item.id] = { ...item, _children: [] };
});
// Build tree structure
flatData.forEach(item => {
if (item.parentId === null) {
tree.push(lookup[item.id]);
} else {
lookup[item.parentId]._children.push(lookup[item.id]);
}
});
return tree;
}
const treeData = buildTree(flatData);interface TreeRowData {
[key: string]: any;
_children?: TreeRowData[];
}
interface DataTreeOptions {
dataTree?: boolean;
dataTreeFilter?: boolean;
dataTreeSort?: boolean;
dataTreeElementColumn?: string | false;
dataTreeBranchElement?: boolean | string | HTMLElement;
dataTreeChildIndent?: number;
dataTreeChildField?: string;
dataTreeCollapseElement?: string | HTMLElement | false;
dataTreeExpandElement?: string | HTMLElement | false;
dataTreeStartExpanded?: boolean | Function | boolean[];
dataTreeChildColumnCalcs?: boolean;
dataTreeSelectPropagate?: boolean;
}
interface TreeStartExpandedFunction {
(row: RowComponent, level: number): boolean;
}Install with Tessl CLI
npx tessl i tessl/npm-tabulator-tables