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>
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>
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>
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>
new Tree()Creates a new Tree component instance.
data Object | ArrayThe 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 BooleanWhether the tree should be editable. Note: This feature is not yet implemented.
Tree.addNode(...nodeClasses) StaticRegister one or more custom node classes. Node classes should extend TreeNode and implement:
static detect(value) — Returns true if this node type should handle the given valuerenderLabel() — Returns a Lit template for the node's label (optional override)getChildren() — Returns null for 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:
true in green, false in rednull in muted grayundefined in muted grayObjects and arrays that don't match any registered node type are rendered as collapsible branches using the default TreeNode behavior.