Tree View
Browse an expandable hierarchy while keeping focus and selection distinct.
Usage
Expanded hierarchy
Browse a realistic project hierarchy while each folder keeps its own independent expansion state.
<!-- Tree View / Expanded -->
<script setup lang="ts">
import { ref } from 'vue'
import { TreeViewDisclosure, TreeViewGroup, TreeViewItem, TreeViewRoot } from '@sectile/vue/tree-view'
const nodes = [
{ id: 'atlas', parentID: null },
{ id: 'apps', parentID: 'atlas' },
{ id: 'dashboard', parentID: 'apps' },
{ id: 'overview', parentID: 'dashboard' },
{ id: 'settings', parentID: 'dashboard' },
{ id: 'packages', parentID: 'atlas' },
{ id: 'tokens', parentID: 'packages' },
]
const expandedValues = ref(['atlas', 'apps', 'dashboard', 'packages'])
</script>
<template>
<TreeViewRoot
:nodes="nodes"
v-model:expanded-values="expandedValues"
:default-value="['settings']"
label="Atlas project files"
>
<TreeViewItem value="atlas"><TreeViewDisclosure for="atlas" as="button">Toggle</TreeViewDisclosure>Atlas workspace</TreeViewItem>
<TreeViewGroup for="atlas">
<TreeViewItem value="apps"><TreeViewDisclosure for="apps" as="button">Toggle</TreeViewDisclosure>Applications</TreeViewItem>
<TreeViewGroup for="apps">
<TreeViewItem value="dashboard"><TreeViewDisclosure for="dashboard" as="button">Toggle</TreeViewDisclosure>Dashboard</TreeViewItem>
<TreeViewGroup for="dashboard">
<TreeViewItem value="overview">Overview.vue</TreeViewItem>
<TreeViewItem value="settings">Settings.vue</TreeViewItem>
</TreeViewGroup>
</TreeViewGroup>
<TreeViewItem value="packages"><TreeViewDisclosure for="packages" as="button">Toggle</TreeViewDisclosure>Packages</TreeViewItem>
<TreeViewGroup for="packages"><TreeViewItem value="tokens">tokens.ts</TreeViewItem></TreeViewGroup>
</TreeViewGroup>
</TreeViewRoot>
</template>Collapsed
Start with descendants hidden, then reveal them without changing the source data.
<!-- Tree View / Collapsed -->
<script setup lang="ts">
import { ref } from 'vue'
import { TreeViewDisclosure, TreeViewGroup, TreeViewItem, TreeViewRoot } from '@sectile/vue/tree-view'
const nodes = [
{ id: 'atlas', parentID: null },
{ id: 'apps', parentID: 'atlas' },
{ id: 'dashboard', parentID: 'apps' },
{ id: 'overview', parentID: 'dashboard' },
{ id: 'settings', parentID: 'dashboard' },
{ id: 'packages', parentID: 'atlas' },
{ id: 'tokens', parentID: 'packages' },
]
const expandedValues = ref(['atlas', 'apps', 'dashboard', 'packages'])
</script>
<template>
<TreeViewRoot
:nodes="nodes"
v-model:expanded-values="expandedValues"
:default-value="['settings']"
label="Atlas project files"
>
<TreeViewItem value="atlas"><TreeViewDisclosure for="atlas" as="button">Toggle</TreeViewDisclosure>Atlas workspace</TreeViewItem>
<TreeViewGroup for="atlas">
<TreeViewItem value="apps"><TreeViewDisclosure for="apps" as="button">Toggle</TreeViewDisclosure>Applications</TreeViewItem>
<TreeViewGroup for="apps">
<TreeViewItem value="dashboard"><TreeViewDisclosure for="dashboard" as="button">Toggle</TreeViewDisclosure>Dashboard</TreeViewItem>
<TreeViewGroup for="dashboard">
<TreeViewItem value="overview">Overview.vue</TreeViewItem>
<TreeViewItem value="settings">Settings.vue</TreeViewItem>
</TreeViewGroup>
</TreeViewGroup>
<TreeViewItem value="packages"><TreeViewDisclosure for="packages" as="button">Toggle</TreeViewDisclosure>Packages</TreeViewItem>
<TreeViewGroup for="packages"><TreeViewItem value="tokens">tokens.ts</TreeViewItem></TreeViewGroup>
</TreeViewGroup>
</TreeViewRoot>
</template>Multiple selection
Choose several files for review without confusing selection with folder expansion.
<!-- Tree View / Multiple -->
<script setup lang="ts">
import { ref } from 'vue'
import { TreeViewDisclosure, TreeViewGroup, TreeViewItem, TreeViewRoot } from '@sectile/vue/tree-view'
const nodes = [
{ id: 'atlas', parentID: null },
{ id: 'apps', parentID: 'atlas' },
{ id: 'dashboard', parentID: 'apps' },
{ id: 'overview', parentID: 'dashboard' },
{ id: 'settings', parentID: 'dashboard' },
{ id: 'packages', parentID: 'atlas' },
{ id: 'tokens', parentID: 'packages' },
]
const expandedValues = ref(['atlas', 'apps', 'dashboard', 'packages'])
</script>
<template>
<TreeViewRoot
:nodes="nodes"
selection-mode="multiple"
v-model:expanded-values="expandedValues"
:default-value="['overview', 'settings', 'tokens']"
label="Files selected for review"
v-slot="{ value }"
>
<output>{{ value.length }} files selected</output>
<TreeViewItem value="atlas"><TreeViewDisclosure for="atlas" as="button">Toggle</TreeViewDisclosure>Atlas workspace</TreeViewItem>
<TreeViewGroup for="atlas">
<TreeViewItem value="apps"><TreeViewDisclosure for="apps" as="button">Toggle</TreeViewDisclosure>Applications</TreeViewItem>
<TreeViewGroup for="apps">
<TreeViewItem value="dashboard"><TreeViewDisclosure for="dashboard" as="button">Toggle</TreeViewDisclosure>Dashboard</TreeViewItem>
<TreeViewGroup for="dashboard">
<TreeViewItem value="overview">Overview.vue</TreeViewItem>
<TreeViewItem value="settings">Settings.vue</TreeViewItem>
</TreeViewGroup>
</TreeViewGroup>
<TreeViewItem value="packages"><TreeViewDisclosure for="packages" as="button">Toggle</TreeViewDisclosure>Packages</TreeViewItem>
<TreeViewGroup for="packages"><TreeViewItem value="tokens">tokens.ts</TreeViewItem></TreeViewGroup>
</TreeViewGroup>
</TreeViewRoot>
</template>Unavailable
Keep an unavailable tree item visible while excluding it from activation.
<!-- Tree View / Unavailable -->
<script setup lang="ts">
import { ref } from 'vue'
import { TreeViewDisclosure, TreeViewGroup, TreeViewItem, TreeViewRoot } from '@sectile/vue/tree-view'
const nodes = [
{ id: 'atlas', parentID: null },
{ id: 'apps', parentID: 'atlas' },
{ id: 'dashboard', parentID: 'apps' },
{ id: 'overview', parentID: 'dashboard' },
{ id: 'settings', parentID: 'dashboard' },
{ id: 'packages', parentID: 'atlas' },
{ id: 'tokens', parentID: 'packages' },
]
const expandedValues = ref(['atlas', 'apps', 'dashboard', 'packages'])
</script>
<template>
<TreeViewRoot
:nodes="nodes"
v-model:expanded-values="expandedValues"
:default-value="['settings']"
label="Atlas project files"
>
<TreeViewItem value="atlas"><TreeViewDisclosure for="atlas" as="button">Toggle</TreeViewDisclosure>Atlas workspace</TreeViewItem>
<TreeViewGroup for="atlas">
<TreeViewItem value="apps"><TreeViewDisclosure for="apps" as="button">Toggle</TreeViewDisclosure>Applications</TreeViewItem>
<TreeViewGroup for="apps">
<TreeViewItem value="dashboard"><TreeViewDisclosure for="dashboard" as="button">Toggle</TreeViewDisclosure>Dashboard</TreeViewItem>
<TreeViewGroup for="dashboard">
<TreeViewItem value="overview">Overview.vue</TreeViewItem>
<TreeViewItem value="settings">Settings.vue</TreeViewItem>
</TreeViewGroup>
</TreeViewGroup>
<TreeViewItem value="packages"><TreeViewDisclosure for="packages" as="button">Toggle</TreeViewDisclosure>Packages</TreeViewItem>
<TreeViewGroup for="packages"><TreeViewItem value="tokens">tokens.ts</TreeViewItem></TreeViewGroup>
</TreeViewGroup>
</TreeViewRoot>
</template>Controlled
Let the parent own the current value and apply accepted changes back to the component.
<!-- Tree View / Controlled -->
<script setup lang="ts">
import { ref } from 'vue'
import { TreeViewDisclosure, TreeViewGroup, TreeViewItem, TreeViewRoot } from '@sectile/vue/tree-view'
const nodes = [
{ id: 'atlas', parentID: null },
{ id: 'apps', parentID: 'atlas' },
{ id: 'dashboard', parentID: 'apps' },
{ id: 'overview', parentID: 'dashboard' },
{ id: 'settings', parentID: 'dashboard' },
{ id: 'packages', parentID: 'atlas' },
{ id: 'tokens', parentID: 'packages' },
]
const expandedValues = ref(['atlas', 'apps', 'dashboard', 'packages'])
</script>
<template>
<TreeViewRoot
:nodes="nodes"
v-model:expanded-values="expandedValues"
:default-value="['settings']"
label="Atlas project files"
>
<TreeViewItem value="atlas"><TreeViewDisclosure for="atlas" as="button">Toggle</TreeViewDisclosure>Atlas workspace</TreeViewItem>
<TreeViewGroup for="atlas">
<TreeViewItem value="apps"><TreeViewDisclosure for="apps" as="button">Toggle</TreeViewDisclosure>Applications</TreeViewItem>
<TreeViewGroup for="apps">
<TreeViewItem value="dashboard"><TreeViewDisclosure for="dashboard" as="button">Toggle</TreeViewDisclosure>Dashboard</TreeViewItem>
<TreeViewGroup for="dashboard">
<TreeViewItem value="overview">Overview.vue</TreeViewItem>
<TreeViewItem value="settings">Settings.vue</TreeViewItem>
</TreeViewGroup>
</TreeViewGroup>
<TreeViewItem value="packages"><TreeViewDisclosure for="packages" as="button">Toggle</TreeViewDisclosure>Packages</TreeViewItem>
<TreeViewGroup for="packages"><TreeViewItem value="tokens">tokens.ts</TreeViewItem></TreeViewGroup>
</TreeViewGroup>
</TreeViewRoot>
</template>API
Vue package: @sectile/vue/tree-view
TreeViewRootTreeViewGroupTreeViewItemTreeViewDisclosure
Props
TreeViewRootProps
asElement or component rendered for this part.
asChildWhether to merge this part into its single child instead of rendering a wrapper.
defaultExpandedValuesInitially expanded values for uncontrolled state.
defaultHighlightedValueInitially highlighted value for uncontrolled state.
defaultValueInitial value used when the component owns its state.
disabledWhether interaction is unavailable.
disabledItemsItem values excluded from focus and selection.
expandedValuesControlled values whose descendants are visible.
highlightedValueValue currently highlighted for keyboard interaction.
labelAccessible name announced for the control.
modelValueCurrent value when state is controlled by the parent.
nodesFlat hierarchy used to build the tree.
policiesBehavior policies that customize validation, movement, or selection.
readonlyWhether the value can be inspected but not changed.
selectionModeWhether selection contains one value or multiple values.
TreeViewPartProps
asElement or component rendered for this part.
asChildWhether to merge this part into its single child instead of rendering a wrapper.
TreeViewGroupProps
asElement or component rendered for this part.
asChildWhether to merge this part into its single child instead of rendering a wrapper.
forValue or ID of the related part targeted by this component.
Slots
TreeViewRootSlotProps
disabledWhether interaction is unavailable.
expandedValuesValues whose descendants are visible.
highlightedValueValue currently highlighted for interaction.
readonlyWhether the value can be inspected but not changed.
valueCurrent value exposed by this contract.
TreeViewItemSlotProps
disabledWhether interaction is unavailable.
expandedWhether descendants are visible.
expandedValuesValues whose descendants are visible.
highlightedWhether this item is highlighted for interaction.
highlightedValueValue currently highlighted for interaction.
readonlyWhether the value can be inspected but not changed.
selectedWhether this item is selected.
selectedValuesCurrent selected values.
valueCurrent value exposed by this contract.
Events
TreeViewRoot
update:expandedValuesEmitted when the requested expanded values change.
update:highlightedValueEmitted when the requested highlighted value changes.
update:modelValueEmitted when the component requests a new controlled value.
Other types
TreeViewPolicies
| Name | Type | Required |
|---|---|---|
eligible | (id: ID) => boolean | — |
TreeViewEligiblePredicate
type TreeViewEligiblePredicate<ID extends string = string> = NonNullable<TreeViewPolicies<ID>['eligible']>TreeViewValueChangeHandler
type TreeViewValueChangeHandler = (value: readonly string[]) => voidTreeViewExpandedValuesChangeHandler
type TreeViewExpandedValuesChangeHandler = (value: readonly string[]) => voidTreeViewHighlightedValueChangeHandler
type TreeViewHighlightedValueChangeHandler = (value: string | null) => voidTreeNodeInput
| Name | Type | Required |
|---|---|---|
id | ID | Yes |
parentID | ID | null | Yes |
TreeViewSelectionMode
type TreeViewSelectionMode = 'single' | 'multiple'Parts
Shared scope: [data-scope="tree-view"]. Combine it with a part selector to keep styles local to this component.
| Part | Selector | Role | Extra attributes |
|---|---|---|---|
root | [data-part="root"] | Defines the component boundary and owns its composed parts. | — |
group | [data-part="group"] | Groups related child items. | — |
item | [data-part="item"] | Represents one selectable or actionable item. | — |
disclosure | [data-part="disclosure"] | Expands or collapses child content. | — |
Keyboard interaction
| Key | Behavior |
|---|---|
| Arrow Up / Arrow Down | Move between visible tree items. |
| Arrow Right | Expand a branch or move into its first child. |
| Arrow Left | Collapse a branch or move to its parent. |
| Enter / Space | Select or activate the current item. |
Accessibility
Tree items expose level, expansion, selection, and disabled state with one roving tab stop.
See the corresponding WAI-ARIA pattern for the host accessibility contract.
