Treeview
A compound component for building accessible hierarchical tree interfaces with expand/collapse and selection support.
Usage
The Treeview component provides a compound pattern for building accessible tree structures. It uses the createNested composable internally for hierarchical state management — tracking parent-child relationships, open/close state, and cascade selection.
- Fruits
- Vegetables
- Bread
<script setup lang="ts">
import { Treeview } from '@vuetify/v0'
const items = [
{
name: 'Fruits',
children: [
{ name: 'Apple' },
{ name: 'Banana' },
{ name: 'Orange' },
],
},
{
name: 'Vegetables',
children: [
{ name: 'Carrot' },
{ name: 'Broccoli' },
],
},
{ name: 'Bread' },
]
</script>
<template>
<Treeview.Root multiple>
<Treeview.List class="text-sm text-on-surface select-none">
<Treeview.Item
v-for="item in items"
:key="item.name"
class="py-0.5"
:value="item.name"
>
<div class="inline-flex items-center gap-1.5">
<Treeview.Activator
v-if="item.children"
class="inline-flex items-center border-none bg-transparent p-0 cursor-pointer text-on-surface hover:text-primary"
>
<Treeview.Cue v-slot="{ attrs }">
<svg
v-bind="attrs"
class="size-3.5 opacity-60 transition-transform data-[state=open]:rotate-90"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
><path d="M9 5l7 7-7 7" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" /></svg>
</Treeview.Cue>
</Treeview.Activator>
<span v-else class="inline-block w-3.5" />
<Treeview.Checkbox v-slot="{ attrs, isSelected, isMixed }" renderless>
<span
v-bind="attrs"
class="size-4 inline-flex items-center justify-center border rounded-sm text-xs leading-none cursor-pointer shrink-0"
:class="isSelected || isMixed ? 'bg-primary text-on-primary border-primary' : 'border-on-surface/40'"
>{{ isMixed ? '−' : isSelected ? '✓' : '\u00A0' }}</span>
</Treeview.Checkbox>
<span>{{ item.name }}</span>
</div>
<Treeview.Content v-if="item.children">
<Treeview.Group class="pl-5">
<Treeview.Item
v-for="child in item.children"
:key="child.name"
class="py-0.5"
:value="child.name"
>
<div class="inline-flex items-center gap-1.5">
<span class="inline-block w-3.5" />
<Treeview.Checkbox v-slot="{ attrs, isSelected }" renderless>
<span
v-bind="attrs"
class="size-4 inline-flex items-center justify-center border rounded-sm text-xs leading-none cursor-pointer shrink-0"
:class="isSelected ? 'bg-primary text-on-primary border-primary' : 'border-on-surface/40'"
>{{ isSelected ? '✓' : '\u00A0' }}</span>
</Treeview.Checkbox>
<span>{{ child.name }}</span>
</div>
</Treeview.Item>
</Treeview.Group>
</Treeview.Content>
</Treeview.Item>
</Treeview.List>
</Treeview.Root>
</template>
Anatomy
<script setup lang="ts">
import { Treeview } from '@vuetify/v0'
</script>
<template>
<Treeview.Root>
<Treeview.List>
<Treeview.Item>
<Treeview.Activator>
<Treeview.Cue />
Label
</Treeview.Activator>
<Treeview.Content>
<Treeview.Group>
<Treeview.Item>
<Treeview.Activator>Leaf</Treeview.Activator>
</Treeview.Item>
</Treeview.Group>
</Treeview.Content>
</Treeview.Item>
</Treeview.List>
</Treeview.Root>
</template>For trees with selection, add Treeview.Checkbox and Treeview.Indicator:
<script setup lang="ts">
import { Treeview } from '@vuetify/v0'
</script>
<template>
<Treeview.Root>
<Treeview.List>
<Treeview.Item>
<Treeview.Activator>
<Treeview.Cue />
</Treeview.Activator>
<Treeview.Checkbox>
<Treeview.Indicator />
</Treeview.Checkbox>
Label
<Treeview.Content>
<Treeview.Group>
<Treeview.Item>Leaf</Treeview.Item>
</Treeview.Group>
</Treeview.Content>
</Treeview.Item>
</Treeview.List>
</Treeview.Root>
</template>Examples
Settings Panel
A settings tree with functional controls built from reactive data. Click any setting to activate it and view its description in the detail pane.
Activation —
activatefrom theItemslot highlights the current item. Style the active row with[data-active].Functional controls — toggles and
<select>dropdowns modify the reactive data directly.Disabled —
:disabledonTreeview.Itemgreys out the “Experimental” category. Style with[data-disabled].Depth indentation —
--v0-treeview-depthCSS variable on each item drivespadding-left, no manual nesting needed.Open/closed —
isOpenslot prop onItemrotates the chevron via a CSS class.Recursive rendering —
SettingNode.vuehandles both categories and leaves, recursing throughTreeview.Groupfor nested children.
Click a setting to see its description.
Recipes
Cascade Selection
Add v-model to Treeview.Root for cascade selection. Use Treeview.Checkbox and Treeview.Indicator for tri-state checkboxes. Use Treeview.SelectAll for a tree-wide toggle.
<script setup lang="ts">
import { Treeview } from '@vuetify/v0'
import { ref } from 'vue'
const selected = ref<string[]>([])
</script>
<template>
<Treeview.Root v-model="selected">
<Treeview.SelectAll>
<Treeview.Indicator />
Select All
</Treeview.SelectAll>
<Treeview.List>
<Treeview.Item value="users">
<Treeview.Checkbox>
<Treeview.Indicator />
</Treeview.Checkbox>
Users
<Treeview.Group>
<Treeview.Item value="users:view">
<Treeview.Checkbox>
<Treeview.Indicator />
</Treeview.Checkbox>
View
</Treeview.Item>
<Treeview.Item value="users:create">
<Treeview.Checkbox>
<Treeview.Indicator />
</Treeview.Checkbox>
Create
</Treeview.Item>
</Treeview.Group>
</Treeview.Item>
</Treeview.List>
</Treeview.Root>
</template>Styling with Data Attributes
All sub-components expose data attributes for CSS-driven state styling:
| Component | Attribute | Values |
|---|---|---|
| Item | data-selected | Present when selected |
| Item | data-disabled | Present when disabled |
| Item | data-open | Present when expanded |
| Item | data-active | Present when active |
| Activator | data-disabled | Present when disabled |
| Activator | data-open | Present when expanded |
| Checkbox | data-selected | Present when checked |
| Checkbox | data-disabled | Present when disabled |
| Checkbox | data-mixed | Present when indeterminate |
| Cue | data-state | open or closed |
| Indicator | data-state | checked, unchecked, or indeterminate |
The --v0-treeview-depth CSS variable is set on each Item, enabling indentation:
.tree-item {
padding-left: calc(var(--v0-treeview-depth) * 1rem);
}Treeview.Root
Props
open
NestedOpenMode | undefinedControls how nodes expand: 'multiple' (default) or 'single' (accordion)
selection
NestedSelectionMode | undefinedControls how selection cascades: 'cascade' (default), 'independent', or 'leaf'
Events
update:model-value
[value: T | T[]]Slots
default
TreeviewRootSlotPropsTreeview.Activator
Props
Treeview.Checkbox
Props
Treeview.Content
Props
Treeview.Cue
Props
Treeview.Indicator
Props
Treeview.Item
Props
Slots
default
TreeviewItemSlotProps<V>Treeview.List
Props
multiselectable
boolean | undefinedWhether multiple items can be selected (sets aria-multiselectable)