Tree View
Tier 2: Light-DOMWAI-ARIA APG hierarchical folder and node explorer with 4-way keyboard traversal
Installation
$npx nnui add tree-view
copy$npm install nnui-kit
copyInteractive Preview & Code
-
📁 src
-
📁 components
- 📄 ui-tree.js
- 📄 ui-tabs.js
-
📁 styles
- 📄 components.css
- 📄 index.js
-
📁 components
- 📦 package.json
<ui-tree-view id="demo-tree" selection-mode="single" style="width: 100%; max-width: 340px;">
<ul data-part="tree">
<li data-part="item" data-value="src" aria-expanded="true">
<span data-part="label">📁 src</span>
<ul data-part="group">
<li data-part="item" data-value="components" aria-expanded="true">
<span data-part="label">📁 components</span>
<ul data-part="group">
<li data-part="item" data-value="ui-tree.js"><span data-part="label">📄 ui-tree.js</span></li>
<li data-part="item" data-value="ui-tabs.js"><span data-part="label">📄 ui-tabs.js</span></li>
</ul>
</li>
<li data-part="item" data-value="styles" aria-expanded="false">
<span data-part="label">📁 styles</span>
<ul data-part="group">
<li data-part="item" data-value="components.css"><span data-part="label">📄 components.css</span></li>
</ul>
</li>
<li data-part="item" data-value="index.js"><span data-part="label">📄 index.js</span></li>
</ul>
</li>
<li data-part="item" data-value="package.json"><span data-part="label">📦 package.json</span></li>
</ul>
</ui-tree-view>import React, { useState } from 'react';
import 'nnui-kit'; // Registers universal Light-DOM elements
export default function TreeviewDemo() {
const [tab, setTab] = useState('all');
const [val, setVal] = useState(50);
const [selected, setSelected] = useState('');
const [query, setQuery] = useState('');
return (
<ui-tree-view id="demo-tree" selection-mode="single" style="width: 100%; max-width: 340px;">
<ul data-part="tree">
<li data-part="item" data-value="src" aria-expanded="true">
<span data-part="label">📁 src</span>
<ul data-part="group">
<li data-part="item" data-value="components" aria-expanded="true">
<span data-part="label">📁 components</span>
<ul data-part="group">
<li data-part="item" data-value="ui-tree.js"><span data-part="label">📄 ui-tree.js</span></li>
<li data-part="item" data-value="ui-tabs.js"><span data-part="label">📄 ui-tabs.js</span></li>
</ul>
</li>
<li data-part="item" data-value="styles" aria-expanded="false">
<span data-part="label">📁 styles</span>
<ul data-part="group">
<li data-part="item" data-value="components.css"><span data-part="label">📄 components.css</span></li>
</ul>
</li>
<li data-part="item" data-value="index.js"><span data-part="label">📄 index.js</span></li>
</ul>
</li>
<li data-part="item" data-value="package.json"><span data-part="label">📦 package.json</span></li>
</ul>
</ui-tree-view>
);
}<script setup>
import { ref } from 'vue';
import 'nnui-kit'; // Registers universal Light-DOM elements
const activeTab = ref('all');
const sliderValue = ref(50);
const selected = ref('');
const query = ref('');
const handleSelect = (val) => {
console.log('Selected:', val);
};
</script>
<template>
<ui-tree-view id="demo-tree" selection-mode="single" style="width: 100%; max-width: 340px;">
<ul data-part="tree">
<li data-part="item" data-value="src" aria-expanded="true">
<span data-part="label">📁 src</span>
<ul data-part="group">
<li data-part="item" data-value="components" aria-expanded="true">
<span data-part="label">📁 components</span>
<ul data-part="group">
<li data-part="item" data-value="ui-tree.js"><span data-part="label">📄 ui-tree.js</span></li>
<li data-part="item" data-value="ui-tabs.js"><span data-part="label">📄 ui-tabs.js</span></li>
</ul>
</li>
<li data-part="item" data-value="styles" aria-expanded="false">
<span data-part="label">📁 styles</span>
<ul data-part="group">
<li data-part="item" data-value="components.css"><span data-part="label">📄 components.css</span></li>
</ul>
</li>
<li data-part="item" data-value="index.js"><span data-part="label">📄 index.js</span></li>
</ul>
</li>
<li data-part="item" data-value="package.json"><span data-part="label">📦 package.json</span></li>
</ul>
</ui-tree-view>
</template><script>
import 'nnui-kit';
let activeTab = $state('all');
let sliderValue = $state(50);
let selected = $state('');
</script>
<ui-tree-view id="demo-tree" selection-mode="single" style="width: 100%; max-width: 340px;">
<ul data-part="tree">
<li data-part="item" data-value="src" aria-expanded="true">
<span data-part="label">📁 src</span>
<ul data-part="group">
<li data-part="item" data-value="components" aria-expanded="true">
<span data-part="label">📁 components</span>
<ul data-part="group">
<li data-part="item" data-value="ui-tree.js"><span data-part="label">📄 ui-tree.js</span></li>
<li data-part="item" data-value="ui-tabs.js"><span data-part="label">📄 ui-tabs.js</span></li>
</ul>
</li>
<li data-part="item" data-value="styles" aria-expanded="false">
<span data-part="label">📁 styles</span>
<ul data-part="group">
<li data-part="item" data-value="components.css"><span data-part="label">📄 components.css</span></li>
</ul>
</li>
<li data-part="item" data-value="index.js"><span data-part="label">📄 index.js</span></li>
</ul>
</li>
<li data-part="item" data-value="package.json"><span data-part="label">📦 package.json</span></li>
</ul>
</ui-tree-view>How to Utilize
NNUI-KIT components live directly in the document Light DOM. You can use them via declarative HTML, with our first-class React wrapper, or platform-natively in Svelte, Vue, Astro, and HTMX:
React 18 & 19 (Next.js 15 App Router)
import 'nnui-kit/css';
import 'nnui-kit/client';
import { TreeView } from 'nnui-kit/react';Universal Web Components (Vue 3, Svelte 5, Astro, HTMX)
<!-- Automatically registers <ui-tree-view> and <nnui-tree-view> -->
import 'nnui-kit/css';
import 'nnui-kit/client';Platform Features
Zero Shadow DOM
Element lives in the Light DOM. Tailwind and global CSS apply directly.
persist="url | local"
Add declarative persistence attribute to auto-sync state with URL search params.
sync="cross-tab"
Synchronize changes across all open browser tabs via BroadcastChannel.