Skip to page content

Tree

Quasar Tree represents a highly configurable component that displays hierarchical data, such as a table of contents in a tree structure.

Usage

Basic

Basic



Accessibility
v2.25+

QTree follows the WAI-ARIA tree pattern: the component exposes role="tree" and each node header is a role="treeitem" carrying aria-expanded on parents, aria-selected on selectable nodes, aria-checked on ticking ones (including the mixed state of partially ticked parents) and aria-disabled when disabled, while the nested child groups convey the hierarchy. In virtual-scroll mode the rows are rendered flat instead, so each one compensates with aria-level, aria-setsize and aria-posinset. Do give the tree an accessible name by setting aria-label (or aria-labelledby) on the component itself.

The tick checkboxes are pointer affordances only — the keyboard path is Space on the node header (see below), with the state announced through aria-checked. The “no nodes” and “no results” messages use localized strings from the Quasar Language Pack.

Every node the user can see takes part in the roving Tab stop, as the tree pattern requires of a role="treeitem". That includes the nodes nothing happens on (a leaf of a tree with no selection and no ticking) and the disabled ones: a disabled node stays reachable and announces itself through aria-disabled, but nothing acts on it — no selection, no expansion, no lazy loading and not even its own handler.

Keyboard navigation

When a tree node has focus:

  • Arrow Up and Arrow Down move focus through the visible nodes.
  • Arrow Right expands a collapsed parent or moves focus to its first visible child.
  • Arrow Left collapses an expanded parent or moves focus to its parent.
  • Home and End move focus to the first and last visible nodes.
  • Enter performs the node’s default action; Space toggles its expansion — or its checkbox, on tickable nodes (when using a tick-strategy). Both do nothing on a disabled node.

No connector lines

Dense
v2.2.4+

Dense



Force dark mode

Perf considerations
v2.25+

Starting with Quasar v2.25, QTree only pays for what is on screen: a collapsed node’s children are not rendered until the node gets expanded for the first time (afterwards they are kept in the DOM — hidden — so that collapsing/expanding can still animate), and a state change (expanding, ticking, selecting, filtering, keyboard navigation) re-renders only the affected nodes. Rendering cost thus scales with the number of visible nodes, not with the total tree size — most trees need no tuning at all. If your code queried the DOM for the children of never-expanded nodes, it needs to expand those nodes first.

When a lot of nodes are visible at the same time, the sheer amount of DOM becomes the bottleneck. There are two remedies, in increasing order of effect:

  1. The no-transition Boolean prop turns off the expand/collapse animation, which also allows QTree to drop collapsed subtrees from the DOM instead of keeping them alive for animating (on older Quasar versions it is the only way to avoid rendering collapsed content altogether). Recommended when using relatively large data.
<q-tree no-transition ...
  1. The virtual-scroll Boolean prop (see the Virtual scroll section below) keeps only the rows around the scrolling viewport in the DOM. This is the mode for really big trees: mounting, expanding all nodes and filtering stay at a constant cost no matter how much of the tree is expanded.

Virtual scroll
v2.25+

The virtual-scroll Boolean prop renders the visible nodes as a flat virtualized list: only the rows around the scrolling viewport (plus a configurable buffer — see the virtual-scroll-* props) exist in the DOM, so rendering cost stays constant regardless of how many nodes are expanded. The example below runs a fully expanded tree of 4,680 nodes; even the largest trees mount, expand-all and filter in milliseconds in this mode.

Things to be aware of in this mode:

  • The tree itself becomes the scrolling container, so give it a height (through CSS) — or point virtual-scroll-target to a scrolling ancestor instead.
  • Expanding and collapsing are instant: there is no slide transition, so the duration and no-transition props and the @after-show/@after-hide events do not apply.
  • The scrollTo method scrolls any visible node’s row into view; keyboard navigation does this automatically.

Integrated example

More info: QSplitter, QTabPanels.

Customize content

Notice (in the example below) the default header and body slot customization.

Notice (in the example below) the custom header and body slots.

WARNING

Clicking or pressing ENTER on the custom header selects the tree item (and the custom header is blurred). Pressing SPACE toggles its expansion.

If you don’t want this to happen just wrap the content of the custom header in a <div @click.stop @keydown.stop> (or add the listeners to the respective component/element that is emitting them).

Accordion, filtering and selectable

In the example below, sibling nodes get contracted when one gets expanded.

Lazy loading

Selection vs ticking, expansion

  • Selection (through QTree selected prop) refers to the currently selected node (gets highlighted with different background).
  • Ticking (through QTree ticked prop) refers to the checkbox associated with each node.
  • Expansion (through QTree expanded prop) refers to the nodes that are expanded.

All properties above require to be dynamically bound using v-model:<prop_name> directive in order for them to work correctly (example: v-model:expanded).

Tick strategy

There are three ticking strategy: ‘leaf’, ‘leaf-filtered’, ‘strict’ with an additional (and default) ‘none’ which disables ticking.

StrategyDescription
leafTicked nodes are only the leaves. Ticking a node influences the parent’s ticked state too (parent becomes partially ticked or ticked), as well as its children (all tickable children become ticked).
leaf-filteredSame concept as leaf, only that this strategy applies only to filtered nodes (the nodes that remain visible after filtering).
strictTicked nodes are independent of parent or children tick state.

You can apply a global tick strategy for a QTree and locally change the ticking strategy for a certain node by specifying the tickStrategy in the nodes model.

Partially ticked nodes
v2.25+

With the leaf and leaf-filtered strategies, a parent whose tickable children are only partly ticked is neither ticked nor unticked, so it does not show up in the ticked model. Use the getIndeterminateNodes() method to get such nodes (in the order of the nodes model), or isIndeterminate(key) to check one of them.

Both always report nothing for the strict strategy, where a node’s tick state is independent of its children.

When you need all three states at once, getTickState(key) returns them in the tri-state form that a QCheckbox takes as its model: true when ticked, null when partially ticked and false when unticked. It is the very value that the node’s own tickbox gets, so it can be bound to a QCheckbox of yours as is.

The header and body slots also get an indeterminate boolean in their scope, next to the ticked one. It is read-only — a node becomes partially ticked through its children, so tick those instead.

Custom filter method

You can customize the filtering method by specifying the filter-method prop. The method below filters by input if it also has ‘(*)’:

Nodes model structure

The following describes a node’s properties that are taken into account by QTree’s v-model.

Node PropertyTypeBehavior when not presentDescription
<nodeKey>String, NumberAn error is generatedNode’s key. The key is picked from the key specified in nodeKey property.
labelStringThe item has no labelNode’s label. When labelKey prop is set the label is picked from that key.
iconStringThe default icon is usedNode’s icon.
iconColorStringThe inherited color is usedNode’s icon color. One from Quasar Color Palette.
imgStringNo image is displayedNode’s image. Use /public folder. Example: ‘mountains.png’
avatarStringNo avatar is displayedNode’s avatar. Use /public folder. Example: ‘boy-avatar.png’
childrenArrayThis node has no sub-nodesArray of nodes as children.
disabledBooleanThe node is enabledIs node disabled?
expandableBooleanThe node is expandableIs node expandable?
selectableBooleanThe node is selectableIs node selectable?
handlerFunctionNo extra function is calledCustom function that should be called on click on node. Receives node as parameter.
tickableBooleanThe node is tickable according to tick strategyWhen using a tick strategy, each node shows a checkbox. Should a node’s checkbox be disabled?
noTickBooleanNode displays a checkboxWhen using a tick strategy, should node display a checkbox?
tickStrategyStringTick strategy ‘none’ is usedOverride global tick strategy for this node only. One of ‘leaf’, ‘leaf-filtered’, ‘strict’, ‘none’.
lazyBooleanChildren are not lazy loadedShould children be lazy loaded? In this case also don’t specify ‘children’ prop.
headerStringSlot ‘default-header’ is usedNode header scoped slot name, without the required ‘header-’ prefix. Example: ‘story’ refers to ‘header-story’ scoped slot.
bodyStringSlot ‘default-body’ is usedNode body scoped slot name, without the required ‘body-’ prefix. Example: ‘story’ refers to ‘body-story’ scoped slot.