Basic Usage
Create a tree using the k-tree component. Set your data by setting the data property.
<k-tree id="myTree"></k-tree>
<script type="module">
import Tree from '/src/components/Tree.js';
const tree = document.getElementById('myTree');
tree.data = {
name: 'John Doe',
age: 30,
active: true,
hobbies: ['reading', 'coding'],
address: {
street: '123 Main St',
city: 'New York'
}
};
</script>
Controlling Initial Depth
Use the depth attribute to control how many levels of branches are open by default. This example
shows depth set to 2:
<k-tree id="depthTree" depth="2"></k-tree>
<script type="module">
import Tree from '/src/components/Tree.js';
const tree = document.getElementById('depthTree');
tree.data = {
company: 'Tech Corp',
departments: {
engineering: {
frontend: ['Alice', 'Bob'],
backend: ['Charlie', 'Diana']
},
sales: {
team: ['Eve', 'Frank']
}
}
};
</script>
Custom Node Types
You can define custom node types to handle specific data. Create a class that extends
TreeNode, implement a static detect method, and override renderLabel()
and/or getChildren(), then register it with Tree.addNode().
<k-tree id="customTree"></k-tree>
<script type="module">
import Tree, { TreeNode } from '/src/components/Tree.js';
import { html } from '/src/lit-all.min.js';
class DateNode extends TreeNode {
renderLabel(){
const { month, day, year } = this.value;
return html`<span class="tc-warning">📅 ${month}/${day}/${year}</span>`;
}
getChildren(){ return null; }
static detect = value => {
return typeof value === 'object'
&& value !== null
&& 'month' in value
&& 'day' in value
&& 'year' in value;
};
}
Tree.addNode(DateNode);
const tree = document.getElementById('customTree');
tree.data = {
event: 'Tech Conference 2025',
startDate: { month: 10, day: 15, year: 2025 },
endDate: { month: 10, day: 17, year: 2025 },
location: 'San Francisco',
attendees: 250
};
</script>
Directory Example
This example uses the
File System Access API.
FileHandleNode and DirHandleNode detect
FileSystemFileHandle and FileSystemDirectoryHandle directly —
no data transformation needed. DirHandleNode loads its children asynchronously
using a reactive internal property, so the tree populates lazily as nodes are opened.
<button id="browseBtn">Browse Directory</button>
<k-tree id="dirTree" depth="1"></k-tree>
<script type="module">
import Tree, { TreeNode } from '/src/components/Tree.js';
import { html } from '/src/lit-all.min.js';
class FileHandleNode extends TreeNode {
render(){
const ext = this.value.name.split('.').pop().toLowerCase();
const iconName = { js: 'code', html: 'code_blocks', css: 'code',
json: 'file-text', md: 'file-text' }[ext] ?? 'file';
return html`<span class="d-b"><k-icon name="${iconName}"></k-icon> ${this.value.name}</span>`;
}
getChildren(){ return null; }
static detect = v => v instanceof FileSystemFileHandle;
}
class DirHandleNode extends TreeNode {
static properties = { ...TreeNode.properties, entries: { state: true } };
connectedCallback(){
super.connectedCallback();
(async () => {
const entries = [];
for await(const [name, handle] of this.value.entries())
entries.push([name, handle]);
this.entries = entries;
})();
}
getChildren(){ return this.entries ?? []; }
renderIcon(){
return html`<k-icon name="${this.opened ? 'folder-open' : 'folder'}"></k-icon>`;
}
render(){
const children = this.getChildren();
return html`
<div>
<button class="branch-label no-btn" @click=${this.toggle} aria-expanded="${this.opened}">
${this.renderIcon()} ${this.value.name}
</button>
${this.opened ? html`<div class="pl">${children.map(([k, v]) => Tree.renderValue(v, k, this.depth + 1, this.maxDepth))}</div>` : ''}
</div>
`;
}
static detect = v => v instanceof FileSystemDirectoryHandle;
}
Tree.addNode(FileHandleNode, DirHandleNode);
document.getElementById('browseBtn').onclick = async () => {
const handle = await showDirectoryPicker();
document.getElementById('dirTree').data = handle;
};
</script>
JavaScript Reference
Constructor
Extends ShadowComponent
new Tree()
Creates a new Tree component instance.
Requirements
- ShadowComponent
- lit-all.min.js
Properties
data Object | Array
The data to display in the tree. Can be any JavaScript object or array. Nested objects and arrays will be rendered as collapsible branches.
depth Number default: 0
The number of branch levels that should be open by default. A value of 0 means all branches are
closed, 1 means the first level is open, 2 means the first two levels are open, etc.
This property is reflected as an attribute.
editable Boolean
Whether the tree should be editable. Note: This feature is not yet implemented.
Methods
Tree.addNode(...nodeClasses) Static
Register one or more custom node classes. Node classes should extend TreeNode and implement:
static detect(value)— Returnstrueif this node type should handle the given valuerenderLabel()— Returns a Lit template for the node's label (optional override)getChildren()— Returnsnullfor leaf behavior, or an array of[key, value]pairs to render children (optional override)renderIcon()— Returns a Lit template for the branch toggle icon (optional override)
Nodes are checked in order of registration (most recently added first).
The Tree component comes with built-in node types for JavaScript primitives:
- StringNode — Renders strings in green with quotes
- NumberNode — Renders numbers in blue
- BooleanNode — Renders
truein green,falsein red - NullNode — Renders
nullin muted gray - UndefinedNode — Renders
undefinedin muted gray
Objects and arrays that don't match any registered node type are rendered as collapsible branches using the default TreeNode behavior.