Tree view
Nested items with expandable branches and selectable rows.
Usage
<script lang="ts">
import { TreeView } from 'bref-ui';
const items = [
{
id: 'projects',
label: 'Projects',
children: [{ id: 'notes', label: 'Notes' }]
}
];
let selection = $state<string>();
</script>
<TreeView {items} label="Files" bind:selection />
Selection and expansion
Labels share an icon column, and each nesting level advances by the disclosure column. Selected rows use a quiet fill; touch controls receive larger targets.
Live preview
Projects and shared files
Settings
View generated code
<script lang="ts">
import { TreeView } from 'bref-ui';
import type { TreeItemProps, TreeSectionProps } from 'bref-ui/types';
let items = $state<TreeItemProps[]>([]);
let sections = $state<TreeSectionProps[]>([
{
id: 'workspace',
label: 'Workspace',
description: 'Projects and shared files',
icon: {
name: 'folder'
},
items: [
{
id: 'projects',
label: 'Projects',
icon: {
name: 'folder'
},
children: [
{
id: 'design',
label: 'Design',
children: [
{
id: 'tokens',
label: 'Tokens'
},
{
id: 'components',
label: 'Components'
}
]
},
{
id: 'archive',
label: 'Archive',
disabled: true,
children: [
{
id: 'past-work',
label: 'Past work'
}
]
}
]
}
]
},
{
id: 'personal',
label: 'Personal',
icon: {
name: 'home'
},
items: [
{
id: 'settings',
label: 'Settings',
icon: {
name: 'settings'
}
}
]
}
]);
let selection = $state<string | string[]>('tokens');
</script>
<TreeView
{items}
{sections}
bind:selection
label={'Interactive files'}
size="medium"
glass={false}
defaultExpanded={true}
/>
<p role="status">
Selected: {Array.isArray(selection) ? selection.join(', ') || 'none' : selection || 'none'}
</p>
Initially expanded remounts the preview because it sets each branch's initial state. Custom link nodes own their own interaction behavior.
Selecting an item does not expand its ancestors. Collapse Projects, then select Tokens to check that the branch stays closed.
Nested, disabled and empty states
Disabled Archive cannot be selected or deleted. Its disclosure remains available, and its child can be selected.
An empty tree renders no rows. Custom node snippets own their styling and behavior.
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
items | TreeItemProps[] | Yes | — | Nested items with id, label, optional icon, children and disabled. IDs must be unique across the component. |
sections | TreeSectionProps[] | No | [] | Ordered headers with id, label, optional description and icon, and their own items array. |
label | string | No | Tree view | Accessible name for the group of items. |
size | BaseSize | No | medium | small, medium or large. |
glass | boolean | No | false | Use glass on selected soft surfaces, including nested items. |
selection | string | string[] | No | Omitted | Bindable selected IDs. A string selects one item; an array toggles individual items independently. |
defaultExpanded | boolean | No | false | Sets the initial open state of each branch. |
onDelete | (id: string) => void | No | Omitted | Shows a delete button for each item; the caller updates the nested data and selection. |
node | Snippet<[TreeItemProps]> | No | Omitted | Replaces each top-level node in items and sections. The snippet owns its links, children, expansion, selection and actions. |
Keyboard and accessibility
Tab and Shift+Tab move between selection buttons, delete buttons and disclosures. Enter or Space activates the focused control. Disabled buttons are skipped. Each branch has a separate expand/collapse button; arrow keys retain browser behavior.
The item label selects; the disclosure marker expands or collapses. An array enables independent multiple selection. Parent selection does not select descendants, and collapse preserves selection. The caller owns data removal and stale selected IDs.
This component uses grouped native buttons by default. Focus follows browser behavior when
items disappear. Selection is bindable; native attributes are not forwarded. Supply a node snippet to render custom links or rows; the snippet owns the entire node, including descendants
and interaction behavior. The documentation sidebar uses this slot for native links and the selected
page's sections.