Tree View
A tree of rows you can open, close and walk with the keyboard.
Walkthrough
1. Basic
A file tree. → opens a folder and steps in, ← closes it and steps out.
src
lib
index.ts 12 KB
utils.ts 3 KB
app.css 28 KB
package.json 2 KB
<script lang="ts"> import { TreeView, type TreeNode } from 'omaris'; const files: TreeNode[] = [ { id: 'src', label: 'src', children: [ { id: 'lib', label: 'lib', children: [ { id: 'index', label: 'index.ts', meta: '12 KB' }, { id: 'utils', label: 'utils.ts', meta: '3 KB' } ] }, { id: 'app', label: 'app.css', meta: '28 KB' } ] }, { id: 'pkg', label: 'package.json', meta: '2 KB' } ]; let expanded = $state(['src', 'lib']); let selected = $state<string | null>('utils');</script><div class="w-72 max-w-full rounded-shape-md border border-border p-2"> <TreeView items={files} bind:expanded bind:selected label="Files" /></div> 2. Checkable
Ticking a branch ticks its leaves, and a partly ticked branch shows a dash. checked holds only the leaf ids, so there is no half state to store.
Food
Grills
Stews
Drinks
Coffee
Tea
grills, coffee
<script lang="ts"> import { TreeView, type TreeNode } from 'omaris'; const categories: TreeNode[] = [ { id: 'food', label: 'Food', children: [ { id: 'grills', label: 'Grills' }, { id: 'stews', label: 'Stews' } ] }, { id: 'drinks', label: 'Drinks', children: [ { id: 'coffee', label: 'Coffee' }, { id: 'tea', label: 'Tea' } ] } ]; let checked = $state(['grills', 'coffee']);</script><div class="flex w-72 max-w-full flex-col gap-3"> <TreeView items={categories} checkable bind:checked defaultExpanded label="Categories" /> <p class="text-xs text-muted-foreground">{checked.join(', ') || 'nothing ticked'}</p></div> 3. Lazy
expandable draws the chevron before the children exist. onexpand is where they get fetched; loading swaps the chevron for a spinner meanwhile.
remote
local
<script lang="ts"> import { TreeView, type TreeNode } from 'omaris'; let items = $state<TreeNode[]>([ { id: 'remote', label: 'remote', expandable: true }, { id: 'local', label: 'local', children: [{ id: 'note', label: 'note.md' }] } ]); let expanded = $state<string[]>([]); function load(node: TreeNode) { if (node.id !== 'remote' || node.children) return; items = items.map((entry) => (entry.id === 'remote' ? { ...entry, loading: true } : entry)); setTimeout(() => { items = items.map((entry) => entry.id === 'remote' ? { ...entry, loading: false, children: [ { id: 'origin', label: 'origin.json' }, { id: 'upstream', label: 'upstream.json' } ] } : entry ); }, 700); }</script><div class="w-72 max-w-full"> <TreeView {items} bind:expanded onexpand={load} label="Sources" /></div> 4. Overridden
A wider indent, pill rows, an accent guide and a row body of your own.
Design open
Tokens
Motion
Code open
API
<script lang="ts"> import { TreeView, type TreeNode } from 'omaris'; const items: TreeNode[] = [ { id: 'design', label: 'Design', children: [ { id: 'tokens', label: 'Tokens' }, { id: 'motion', label: 'Motion' } ] }, { id: 'code', label: 'Code', children: [{ id: 'api', label: 'API' }] } ];</script><div class="w-72 max-w-full"> <TreeView {items} defaultExpanded label="Sections" class="[--tree-indent:2rem]" classes={{ item: 'rounded-full', guide: 'bg-primary/30' }} > {#snippet row(node, { expanded })} <span class="min-w-0 flex-1 truncate font-medium">{node.label}</span> {#if expanded} <span class="text-xs text-muted-foreground">open</span> {/if} {/snippet} </TreeView></div>