Treeview
A hierarchical data visualization element that displays nested information in an expandable, collapsible outline format.
Overview
A treeview component is a hierarchical data visualization element that displays nested information in an expandable, collapsible outline format, commonly used for navigation or selection.
Building on this concept, Quercus.js is an absolute lightweight, dependency-free JavaScript library for rendering interactive treeview structures.
You can add its CDN links by referencing the treeview.css and
treeview.js files directly from a source like GitHub's raw content into your
HTML's <head> and before the closing </body> tag,
respectively.
Examples
Below are some of the examples of a treeview component.
Custom Node Rendering (Add icons, badges, etc.)
This example allows full control over how each node is displayed by customizing its content (e.g. adding icons or status badges) via a rendering callback.
<div id="treeview-custom"></div>
<div id="treeview-custom"></div>
.tree-icon::before {
content: '📁 ';
}
.tree-icon.file::before {
content: '📄 ';
}
.tree-icon.image::before {
content: '🖼️ ';
}
.treeview-node-text {
margin-right: 0.5rem;
}
.tree-icon::before { content: '📁 '; } .tree-icon.file::before { content: '📄 ';
} .tree-icon.image::before { content: '🖼️ '; } .treeview-node-text { margin-right:
0.5rem; }
document.addEventListener('DOMContentLoaded', function () {
const data = [
{
id: 'root',
name: 'Projects',
type: 'folder',
children: [
{
id: 'p1',
name: 'Website',
type: 'folder',
status: 'active',
children: [
{
id: 'p1-1',
name: 'index.html',
type: 'file'
},
{
id: 'p1-2',
name: 'styles.css',
type: 'file'
},
{
id: 'p1-3',
name: 'images',
type: 'folder',
children: [
{
id: 'p1-3-1',
name: 'logo.png',
type: 'image'
},
{
id: 'p1-3-2',
name: 'hero.jpg',
type: 'image'
}
]
}
]
},
{
id: 'p2',
name: 'Mobile App',
type: 'folder',
status: 'paused',
children: [
{
id: 'p2-1',
name: 'app.js',
type: 'file'
}
]
}
]
}
];
new Treeview({
containerId: 'treeview-custom',
data,
initiallyExpanded: true,
onRenderNode: (node, wrapper) => {
wrapper.innerHTML = ''; // Clear existing
const icon = document.createElement('span');
icon.className = 'tree-icon';
// Add icon class based on node type
if (node.type === 'file') {
icon.classList.add('file');
} else if (node.type === 'image') {
icon.classList.add('image');
}
wrapper.appendChild(icon);
const name = document.createElement('span');
name.className = 'treeview-node-text';
name.textContent = node.name;
wrapper.appendChild(name);
if (node.status) {
const badge = document.createElement('span');
badge.className = 'badge text-bg-primary';
badge.textContent = node.status;
wrapper.appendChild(badge);
}
}
});
});
document.addEventListener('DOMContentLoaded', function () { const data = [ { id:
'root', name: 'Projects', type: 'folder', children: [ { id:
'p1', name: 'Website', type: 'folder', status: 'active',
children: [ { id: 'p1-1', name: 'index.html', type: 'file' }, { id:
'p1-2', name: 'styles.css', type: 'file' }, { id: 'p1-3', name:
'images', type: 'folder', children: [ { id: 'p1-3-1', name:
'logo.png', type: 'image' }, { id: 'p1-3-2', name: 'hero.jpg',
type: 'image' } ] } ] }, { id: 'p2', name: 'Mobile App', type:
'folder', status: 'paused', children: [ { id: 'p2-1', name:
'app.js', type: 'file' } ] } ] } ]; new Treeview({ containerId:
'treeview-custom', data, initiallyExpanded: true, onRenderNode: (node, wrapper) => {
wrapper.innerHTML = ''; // Clear existing const icon =
document.createElement('span'); icon.className = 'tree-icon'; // Add icon class
based on node type if (node.type === 'file') { icon.classList.add('file'); }
else if (node.type === 'image') { icon.classList.add('image'); }
wrapper.appendChild(icon); const name = document.createElement('span'); name.className =
'treeview-node-text'; name.textContent = node.name; wrapper.appendChild(name); if
(node.status) { const badge = document.createElement('span'); badge.className =
'badge text-bg-primary'; badge.textContent = node.status; wrapper.appendChild(badge); }
} }); });
Multi-Select and Single-Select
The Multi-Select Tree allows users to pick any number of items, while the Single-Select Tree restricts the user to choosing only one item at a time.
<div id="treeview-multi"></div>
<div id="treeview-single"></div>
<div id="treeview-multi"></div> <div
id="treeview-single"></div>
document.addEventListener('DOMContentLoaded', function() {
const myTreeData = [
{
id: '1',
name: 'Project Root',
selectable: false, // Node cannot be selected
children: [
{
id: '1.1',
name: 'Source Files',
children: [
{ id: '1.1.1', name: 'App.js' },
{ id: '1.1.2', name: 'Styles.css', selected: true } // Initially selected
]
},
{
id: '1.2',
name: 'Assets',
children: [
{ id: '1.2.1', name: 'logo.png' },
{ id: '1.2.2', name: 'data.json' }
]
}
]
},
{
id: '2',
name: 'Documentation'
}
];
// A. Initialize a Multi-Select Tree
const treeMulti = new Treeview({
containerId: 'treeview-multi', // Required: ID of the HTML element
data: myTreeData, // The data array defined above
searchEnabled: true, // Display a search box (default is true)
multiSelectEnabled: true, // Allow multiple nodes to be selected (default is true)
initiallyExpanded: false, // Start with all nodes collapsed
});
// (Optional) Style treeview's auto-generated search input using Bootstrap's 'form-control' class
requestAnimationFrame(() => {
const searchInput = document.querySelector('#treeview-multi input[type="text"]');
if (searchInput) {
searchInput.classList.add('form-control');
}
});
// B. Initialize a Single-Select Tree
const treeSingle = new Treeview({
containerId: 'treeview-single',
data: myTreeData,
multiSelectEnabled: false, // Key change: Enables single-selection mode
initiallyExpanded: true, // Start with all nodes open
});
});
document.addEventListener('DOMContentLoaded', function() { const myTreeData = [ { id:
'1', name: 'Project Root', selectable: false, // Node cannot be selected
children: [ { id: '1.1', name: 'Source Files', children: [ { id:
'1.1.1', name: 'App.js' }, { id: '1.1.2', name: 'Styles.css',
selected: true } // Initially selected ] }, { id: '1.2', name: 'Assets',
children: [ { id: '1.2.1', name: 'logo.png' }, { id: '1.2.2', name:
'data.json' } ] } ] }, { id: '2', name: 'Documentation' } ]; // A.
Initialize a Multi-Select Tree const treeMulti = new Treeview({ containerId:
'treeview-multi', // Required: ID of the HTML element data: myTreeData, // The data
array defined above searchEnabled: true, // Display a search box (default is true)
multiSelectEnabled: true, // Allow multiple nodes to be selected (default is true)
initiallyExpanded: false, // Start with all nodes collapsed }); // (Optional) Style
treeview's auto-generated search input using Bootstrap's 'form-control' class
requestAnimationFrame(() => { const searchInput = document.querySelector('#treeview-multi
input[type="text"]'); if (searchInput) {
searchInput.classList.add('form-control'); } }); // B. Initialize a Single-Select Tree
const treeSingle = new Treeview({ containerId: 'treeview-single', data: myTreeData,
multiSelectEnabled: false, // Key change: Enables single-selection mode initiallyExpanded: true,
// Start with all nodes open }); });
Multi-Select with Checkboxes
This example enables users to select multiple tree nodes using checkboxes, with optional "Select All" and cascading child selection.
<div id="treeview-checkboxes"></div>
<div id="treeview-checkboxes"></div>
document.addEventListener('DOMContentLoaded', function() {
const data = [
{
id: 'courses',
name: 'Courses',
children: [
{ id: 'html', name: 'HTML' },
{ id: 'css', name: 'CSS' },
{ id: 'js', name: 'JavaScript' }
]
},
{
id: 'frameworks',
name: 'Frameworks',
children: [
{ id: 'react', name: 'React' },
{ id: 'vue', name: 'Vue' }
]
}
];
new Treeview({
containerId: 'treeview-checkboxes',
data,
checkboxSelectionEnabled: true,
multiSelectEnabled: true,
cascadeSelectChildren: true,
showSelectAllButton: true,
showInvertSelectionButton: true,
initiallyExpanded: true,
onSelectionChange: (selected) => {
console.log('Checked:', selected);
}
});
// (Optional) Enhance checkboxes with Bootstrap's 'form-check-input' class after treeview renders
requestAnimationFrame(() => {
document.querySelectorAll('#treeview-checkboxes input[type="checkbox"]').forEach(cb => {
cb.classList.add('form-check-input');
});
});
});
document.addEventListener('DOMContentLoaded', function() { const data = [ { id:
'courses', name: 'Courses', children: [ { id: 'html', name:
'HTML' }, { id: 'css', name: 'CSS' }, { id: 'js', name:
'JavaScript' } ] }, { id: 'frameworks', name: 'Frameworks', children: [
{ id: 'react', name: 'React' }, { id: 'vue', name: 'Vue' } ] }
]; new Treeview({ containerId: 'treeview-checkboxes', data, checkboxSelectionEnabled:
true, multiSelectEnabled: true, cascadeSelectChildren: true, showSelectAllButton: true,
showInvertSelectionButton: true, initiallyExpanded: true, onSelectionChange: (selected) => {
console.log('Checked:', selected); } }); // (Optional) Enhance checkboxes with
Bootstrap's 'form-check-input' class after treeview renders requestAnimationFrame(()
=> { document.querySelectorAll('#treeview-checkboxes
input[type="checkbox"]').forEach(cb => {
cb.classList.add('form-check-input'); }); }); });