Tree

Tree component with filtering, single/multi select, and expand controls.

VerifiedSince 0.3.4

Usage

Loading demo...

Best Practices

  • Treat key as the durable identifier. Do not derive it from display labels that may be translated or renamed.
  • Use expandedKeys only when another surface needs to own expansion state; otherwise prefer defaultExpandedKeys.
  • Keep permission-scope trees single-select and move actual grant assignment into TxTransfer, DataTable, or a detail panel.
  • Use filterMethod for domain-specific search such as path aliases or hidden metadata; keep label search for simple trees.
  • If you use leaf=false for lazy-looking placeholders, also provide a loading or empty child state in the surrounding UI. TxTree does not fetch children by itself.
  • When replacing rows with the item slot, call toggleExpand() from the disclosure control and toggleSelect() from the selectable region instead of duplicating state logic.

API Reference

TxTree Props

PropTypeDefaultDescription
nodesTreeNode[][]Hierarchical data source. Nodes are flattened by expanded state and current filter.
modelValuestring | number | Array<string | number>-Selected key for single select, or selected keys when multiple=true. Binding it hands selection to the host; leave it off and the tree keeps its own.
multiplebooleanfalseToggle selected keys as an array instead of replacing with one key.
selectablebooleantrueAllow row and checkbox selection. Expansion controls still work when selection is disabled.
checkablebooleanfalseShow a checkbox for each visible node. Checkbox state mirrors modelValue; it does not cascade to descendants.
disabledbooleanfalseDisable selection for the whole tree and apply disabled row styling. Expansion remains available.
defaultExpandedKeysArray<string | number>[]Initial uncontrolled expanded keys; later prop changes reset internal expansion only when expandedKeys is not controlled.
defaultSelectedKeysArray<string | number>-Initial uncontrolled selection. Ignored entirely while modelValue is bound, the same split defaultExpandedKeys has with expandedKeys.
expandedKeysArray<string | number>-Controlled expanded keys. Parent must update this after update:expandedKeys.
indentnumber16Per-level left padding in pixels.
filterTextstring''Trimmed query used to filter nodes. Matching branches auto-expand while the query is non-empty.
filterMethod(node: TreeNode, query: string) => boolean-Custom matcher. Receives the original trimmed query; default matching uses a lowercased label contains check.

TreeNode

FieldTypeDescription
keystring | numberStable unique key used for selection and expansion.
labelstringDefault row text and default filter target.
childrenTreeNode[]Child nodes.
leafbooleanSet false to render an expandable caret even before child data exists.
disabledbooleanDisable selection for this node; expansion is still allowed for nodes with children.
iconTxIconSource | stringOptional node icon; strings are treated as class icons.

TxTree Events

EventPayloadDescription
update:modelValuevalue: TreeValueEmitted after a selectable node is clicked or its checkbox changes.
select{ key: TreeKey, node: TreeNode }Emitted with the selected node after update:modelValue.
toggle{ key: TreeKey, expanded: boolean }Emitted after a node caret expands or collapses.
update:expandedKeyskeys: TreeKey[]Emitted with the next expanded keys for uncontrolled and controlled expansion flows.

TxTree Slots

SlotPropsDescription
item{ node, level, expanded, hasChildren, selected, toggleExpand, toggleSelect, indent }Replace the full visible row renderer. Call the slot helpers to preserve selection and expansion behavior.
empty-Empty state shown when no visible rows remain after filtering. Defaults to No results.

Admin Permission Scopes

TxTree is a good fit for resource scopes, permission domains, and organization hierarchies in admin pages. Pair it with TxSearchInput, pass the keyword into filterText, and let the selected key drive details, transfer lists, or audit timelines.

Permission orchestration panel

A screenshot-verified Tree / TreeSelect / Transfer / Timeline composition.

Loading demo...

Exposed Methods

None. Control selection and expansion through props and emitted events.

Overview

  • expandedKeys makes expansion controlled. The component still emits update:expandedKeys, but does not mutate internal expansion until the parent passes the new keys back.
  • defaultExpandedKeys seeds uncontrolled expansion and can reset it later while expandedKeys is absent.
  • Selection works the same way. The tree keeps its own selection unless modelValue is bound; defaultSelectedKeys seeds it. Before this, the selected set was derived from modelValue alone, so <TxTree :nodes="…" /> with no binding emitted update:modelValue into nothing and never lit a row — the tree looked clickable and was inert.
  • A seed that changes while modelValue is bound is ignored, so it cannot become the fallback if the host later stops driving the selection.
  • Hovering a selected row keeps its accent. :hover:not(.is-disabled) is (0,3,0) against .is-selected's (0,2,0), so the neutral hover fill used to replace the accent exactly while the pointer was on the row; the hover rule now excludes selected rows and they get their own, stronger, accent shade.
  • Filtering does not mutate expansion state. It temporarily expands ancestors of matching nodes through effectiveExpanded while filterText is non-empty.
  • The default filter checks node.label.toLowerCase().includes(query.toLowerCase()); custom filterMethod receives the trimmed original query.
  • Selection is flat. checkable only changes the control UI; it does not implement parent/child tri-state or descendant cascading.
  • disabled and node.disabled block selection, but caret expansion remains available for expandable nodes.
  • The root uses role="tree" (with aria-multiselectable in multiple mode); each row wrapper is role="treeitem" carrying aria-level, aria-setsize, and aria-posinset (position within its sibling group), plus aria-expanded / aria-selected / aria-disabled as applicable, over a role="presentation" list. The item slot only replaces the inner row visuals, so these row semantics are preserved automatically.

Technologies

  • Reviewed against packages/tuffex/packages/components/src/tree/src/TxTree.vue and types.ts.
  • Existing tests cover expanded rendering, selection events, and the role="treeitem" set/position semantics (aria-setsize / aria-posinset over a presentational list); docs call out untested but source-visible behavior such as filtering expansion, controlled expansion, and non-cascading checkboxes.
  • The permission orchestration example should keep TxTree responsible for scope selection only; assigning resources belongs in adjacent controls.
  • Screenshot reference: .codex-screenshots/nexus-tree-permission-orchestration-demo-playwright-2026-05-28.png.
  • Component source: packages/tuffex/packages/components/src/tree/src/TxTree.vue.
  • Types: packages/tuffex/packages/components/src/tree/src/types.ts.
  • Verified coverage: packages/tuffex/packages/components/src/tree/__tests__/tree.test.ts covers default-expanded child rendering, selection-value emission, and per-sibling aria-setsize / aria-posinset over a role="presentation" list.
查看源码
packages/tuffex/packages/components/src/tree/index.ts

Customization

Theme tokenUsed for
--tx-text-color-primaryDefault row label color.
--tx-text-color-secondaryCaret and empty-state color.
--tx-color-primarySelected row background tint.
--tx-fill-colorHover row background tint.