I’m trying to implement expandable child rows in Tabulator, where each row can have nested child rows that are toggled with a button. The child rows are correctly hidden by default and revealed when the “Show Children” button is clicked, but the layout doesn’t update dynamically when child rows are toggled, unless I manually scroll or resize the window.
Steps to reproduce:
I’ve set up a parent table where each row can have child rows (nested data).
The child rows are initially hidden.
When I click the “Show Children” button, a child table should be dynamically appended below the parent row, and its visibility should toggle.
The issue:
The child rows toggle visibility correctly when clicked, but the table doesn’t update its layout (e.g., row heights or overall layout) until I manually scroll or resize the window.
I’ve tried using table.redraw(true) and resize() methods, but they haven’t solved the problem.
My current code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tabulator - Expandable Child Rows</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/tabulator/5.4.3/css/tabulator.min.css" rel="stylesheet">
</head>
<body>
<h1>Tabulator with Expandable Child Rows</h1>
<div id="example-table"></div>
<script src="https://unpkg.com/tabulator-tables/dist/js/tabulator.min.js"></script>
<script>
// Sample Data
const tableData = [{
id: 1,
name: "Parent 1",
age: 40,
children: [{
id: 11,
name: "Child 1.1",
age: 10
},
{
id: 12,
name: "Child 1.2",
age: 12
}
]
},
{
id: 2,
name: "Parent 2",
age: 35,
children: [{
id: 21,
name: "Child 2.1",
age: 8
},
{
id: 22,
name: "Child 2.2",
age: 6
}
]
},
{
id: 3,
name: "Parent 3",
age: 50,
children: [{
id: 31,
name: "Child 3.1",
age: 15
}]
}
];
// Initialize main Tabulator table
const table = new Tabulator("#example-table", {
data: tableData, // Parent data
layout: "fitColumns",
columns: [{
title: "Name",
field: "name",
sorter: "string",
width: 200
},
{
title: "Age",
field: "age",
sorter: "number",
width: 100
},
{
title: "Children",
field: "children",
formatter: (cell, formatterParams) => {
const children = cell.getValue();
return children && children.length > 0 ?
`<button class="toggle-child">Show Children (${children.length})</button>` :
"No Children";
},
cellClick: (e, cell) => {
const children = cell.getValue();
if (children && children.length > 0) {
const parentElement = cell.getElement();
const toggleButton = parentElement.querySelector(".toggle-child");
let childContainer = parentElement.querySelector(".child-table-container");
if (!childContainer) {
// Create the child table
childContainer = createChildTable(cell, children);
parentElement.appendChild(childContainer);
}
// Toggle visibility
if (childContainer.style.display === "none" || !childContainer.style.display) {
childContainer.style.display = "block";
toggleButton.textContent = `Hide Children`;
} else {
childContainer.style.display = "none";
toggleButton.textContent = `Show Children (${children.length})`;
}
}
}
}
]
});
// Create a child table dynamically
const createChildTable = (parentCell, children) => {
const container = document.createElement("div");
container.className = "child-table-container";
container.style.display = "none"; // Initially hidden
const childTable = new Tabulator(container, {
data: children, // Child data
layout: "fitColumns",
columns: [{
title: "Name",
field: "name",
sorter: "string",
width: 150
},
{
title: "Age",
field: "age",
sorter: "number",
width: 100
}
],
movableColumns: true,
height: "150px"
});
return container;
};
</script>
<style>
.child-table-container {
margin-top: 10px;
display: none;
/* Initially hidden */
}
.toggle-child {
cursor: pointer;
color: blue;
background: none;
border: none;
text-decoration: underline;
}
</style>
</body>
</html>
What I’ve tried:
- table.redraw(true) to force a redraw after toggling child rows.
- resize() method to try to trigger a layout update.
Various DOM manipulations like appending elements and toggling visibility.
However, none of these methods seem to update the layout correctly.
My question:
How can I ensure that the table layout updates properly when toggling child rows in Tabulator? Is there a more appropriate way to handle dynamic updates to the table when child rows are shown or hidden?
Emil Appelkvist is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.