Tree
Tree component with filtering, single/multi select, and expand controls.
Usage
Loading demo...
Best Practices
- Treat
keyas the durable identifier. Do not derive it from display labels that may be translated or renamed. - Use
expandedKeysonly when another surface needs to own expansion state; otherwise preferdefaultExpandedKeys. - Keep permission-scope trees single-select and move actual grant assignment into
TxTransfer,DataTable, or a detail panel. - Use
filterMethodfor domain-specific search such as path aliases or hidden metadata; keeplabelsearch for simple trees. - If you use
leaf=falsefor lazy-looking placeholders, also provide a loading or empty child state in the surrounding UI.TxTreedoes not fetch children by itself. - When replacing rows with the
itemslot, calltoggleExpand()from the disclosure control andtoggleSelect()from the selectable region instead of duplicating state logic.
API Reference
TxTree Props
| Prop | Type | Default | Description |
|---|---|---|---|
nodes | TreeNode[] | [] | Hierarchical data source. Nodes are flattened by expanded state and current filter. |
modelValue | string | 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. |
multiple | boolean | false | Toggle selected keys as an array instead of replacing with one key. |
selectable | boolean | true | Allow row and checkbox selection. Expansion controls still work when selection is disabled. |
checkable | boolean | false | Show a checkbox for each visible node. Checkbox state mirrors modelValue; it does not cascade to descendants. |
disabled | boolean | false | Disable selection for the whole tree and apply disabled row styling. Expansion remains available. |
defaultExpandedKeys | Array<string | number> | [] | Initial uncontrolled expanded keys; later prop changes reset internal expansion only when expandedKeys is not controlled. |
defaultSelectedKeys | Array<string | number> | - | Initial uncontrolled selection. Ignored entirely while modelValue is bound, the same split defaultExpandedKeys has with expandedKeys. |
expandedKeys | Array<string | number> | - | Controlled expanded keys. Parent must update this after update:expandedKeys. |
indent | number | 16 | Per-level left padding in pixels. |
filterText | string | '' | 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
| Field | Type | Description |
|---|---|---|
key | string | number | Stable unique key used for selection and expansion. |
label | string | Default row text and default filter target. |
children | TreeNode[] | Child nodes. |
leaf | boolean | Set false to render an expandable caret even before child data exists. |
disabled | boolean | Disable selection for this node; expansion is still allowed for nodes with children. |
icon | TxIconSource | string | Optional node icon; strings are treated as class icons. |
TxTree Events
| Event | Payload | Description |
|---|---|---|
update:modelValue | value: TreeValue | Emitted 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:expandedKeys | keys: TreeKey[] | Emitted with the next expanded keys for uncontrolled and controlled expansion flows. |
TxTree Slots
| Slot | Props | Description |
|---|---|---|
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
expandedKeysmakes expansion controlled. The component still emitsupdate:expandedKeys, but does not mutate internal expansion until the parent passes the new keys back.defaultExpandedKeysseeds uncontrolled expansion and can reset it later whileexpandedKeysis absent.- Selection works the same way. The tree keeps its own selection unless
modelValueis bound;defaultSelectedKeysseeds it. Before this, the selected set was derived frommodelValuealone, so<TxTree :nodes="…" />with no binding emittedupdate:modelValueinto nothing and never lit a row — the tree looked clickable and was inert. - A seed that changes while
modelValueis 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
effectiveExpandedwhilefilterTextis non-empty. - The default filter checks
node.label.toLowerCase().includes(query.toLowerCase()); customfilterMethodreceives the trimmed original query. - Selection is flat.
checkableonly changes the control UI; it does not implement parent/child tri-state or descendant cascading. disabledandnode.disabledblock selection, but caret expansion remains available for expandable nodes.- The root uses
role="tree"(witharia-multiselectableinmultiplemode); each row wrapper isrole="treeitem"carryingaria-level,aria-setsize, andaria-posinset(position within its sibling group), plusaria-expanded/aria-selected/aria-disabledas applicable, over arole="presentation"list. Theitemslot only replaces the inner row visuals, so these row semantics are preserved automatically.
Technologies
- Reviewed against
packages/tuffex/packages/components/src/tree/src/TxTree.vueandtypes.ts. - Existing tests cover expanded rendering, selection events, and the
role="treeitem"set/position semantics (aria-setsize/aria-posinsetover 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
TxTreeresponsible 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.tscovers default-expanded child rendering, selection-value emission, and per-siblingaria-setsize/aria-posinsetover arole="presentation"list.
查看源码
packages/tuffex/packages/components/src/tree/index.ts
Customization
| Theme token | Used for |
|---|---|
--tx-text-color-primary | Default row label color. |
--tx-text-color-secondary | Caret and empty-state color. |
--tx-color-primary | Selected row background tint. |
--tx-fill-color | Hover row background tint. |