Tree

March 30, 2026 · View on GitHub

Scrollable, hierarchical list widget for tree-structured data. Nodes can be expanded and collapsed. Navigation uses a flattened visible-node list so scrolling and highlighting behave identically to List.

TreeNode

TreeNode is user-created and holds display text, optional opaque data, and child nodes.

Constructor: NewTreeNode(text string, data ...any) *TreeNode

MethodDescription
Add(child *TreeNode) *TreeNodeAppends a child; returns the receiver for chaining
Children() []*TreeNodeReturns direct children
Collapse()Collapses the node
Data() anyReturns the opaque user data
Disabled() boolReports whether the node is non-selectable
Expand()Expands the node
Expanded() boolReports whether the node is expanded
Leaf() boolTrue when the node has no children and no pending loader
SetDisabled(bool)Marks the node as non-selectable
SetLoader(fn NodeLoader) *TreeNodeAttaches a lazy-load function (see Lazy loading)
Text() stringReturns the display text
Toggle()Toggles expanded state

Lazy loading

A node whose children are loaded on first expand is created with NewLazyTreeNode:

func NewLazyTreeNode(text string, loader NodeLoader, data ...any) *TreeNode

NodeLoader is func(node *TreeNode). It is called once when the node is first expanded and is expected to call node.Add for each child. The loader is cleared after the first call so subsequent expand/collapse cycles use the already-loaded children.

SetLoader re-arms a node so the next expand calls the new loader again — useful for refresh.

Tree widget

Constructor: NewTree(id, class string) *Tree

Data methods

MethodDescription
Add(node *TreeNode)Appends a top-level node
Root() *TreeNodeReturns the invisible root (its children are top-level)
SetRoot(root *TreeNode)Replaces the invisible root
MethodDescription
First()Highlights first enabled node
Last()Highlights last enabled node
Move(count int)Moves highlight by count, skipping disabled nodes
PageDown()Moves down by viewport height
PageUp()Moves up by viewport height
Select(node *TreeNode)Highlights the given node if visible
Selected() *TreeNodeReturns the highlighted node, or nil

Expand / collapse methods

MethodDescription
Collapse(node *TreeNode)Collapses node; dispatches "change"
CollapseAll()Collapses every node recursively
Expand(node *TreeNode)Expands node (runs loader if pending); dispatches "change"
ExpandAll()Expands every node recursively

Events

EventDataDescription
"activate"*TreeNodeEnter or Space pressed on a node
"change"*TreeNodeNode was expanded or collapsed
"select"*TreeNodeHighlighted node changed

Notes

Flags: "focusable"

Keyboard:

KeyBehaviour
/ Move highlight; skips disabled nodes
Expand collapsed node with children; move to first child if already expanded
Collapse expanded node; move to parent if collapsed
Enter / SpaceToggle expand/collapse; dispatch "activate"
Home / EndJump to first / last enabled node
PgUp / PgDnMove by viewport height

Mouse: single click moves highlight.

Style selectors:

SelectorApplied to
"tree"Base background and foreground
"tree/highlight"Highlighted row when unfocused
"tree/highlight:focused"Highlighted row when focused
"tree/indent"Indent lines and connector characters
":disabled"Disabled row text

Theme strings:

KeyDefaultDescription
tree.expandedIndicator for an expanded non-leaf node
tree.collapsedIndicator for a collapsed non-leaf node
tree.branch├─Connector for a non-last child
tree.last└─Connector for the last child
tree.trunkVertical continuation line at an ancestor column

TreeFS

TreeFS is a Tree pre-wired for filesystem navigation. It wraps *Tree and loads directory contents lazily on first expand. Directories appear before files within each directory, both sorted alphabetically. Every node's Data() is the absolute path string of the entry.

Constructor: NewTreeFS(id, class, root string, dirsOnly bool) *TreeFS

dirsOnly hides files when true.

MethodDescription
DirsOnly() boolReports whether files are hidden
RootPath() stringReturns the absolute path of the current root directory
SetDirsOnly(bool)Toggles file visibility (takes effect on next unexpanded directory)
SetRoot(path string)Replaces the root directory and resets the tree

TreeFS uses the "tree-fs" selector family, falling back to "tree" styles through the theme cascade.

Read errors (e.g. permission denied) are shown as a single (error message) child node.