TreeView expansion control: content vs iconContainer triggers, controlled expandedItems with expand/collapse-all buttons, and expansion tracking.

Tree Expansion

TreeView expansion control: content vs iconContainer triggers, controlled expandedItems with expand/collapse-all buttons, and expansion tracking.


Overview

TreeView expansion control: content vs iconContainer triggers, controlled expandedItems with expand/collapse-all buttons, and expansion tracking.


Live examples

# File: docs/tree_expansion/demo.py

"""Tree Expansion demo — rendered on /tree-expansion via `.. exec::`.

Ported verbatim from the pre-migration pages/tree_expansion.py (same ids, same callbacks).
"""
import json
from dash import html, callback, Input, Output

from dash_mui_charts import TreeView

DEEP_TREE = [
    {"id": "root-a", "label": "Category A", "children": [
        {"id": "a-1", "label": "Sub A-1", "children": [
            {"id": "a-1-i", "label": "Item A-1-i"},
            {"id": "a-1-ii", "label": "Item A-1-ii"},
        ]},
        {"id": "a-2", "label": "Sub A-2", "children": [
            {"id": "a-2-i", "label": "Item A-2-i"},
        ]},
    ]},
    {"id": "root-b", "label": "Category B", "children": [
        {"id": "b-1", "label": "Sub B-1"},
        {"id": "b-2", "label": "Sub B-2", "children": [
            {"id": "b-2-i", "label": "Item B-2-i"},
            {"id": "b-2-ii", "label": "Item B-2-ii"},
        ]},
    ]},
    {"id": "root-c", "label": "Category C", "children": [
        {"id": "c-1", "label": "Sub C-1"},
    ]},
]

ALL_PARENT_IDS = ["root-a", "a-1", "a-2", "root-b", "b-2", "root-c"]

section_style = {'marginBottom': '40px'}
output_style = {
    'fontSize': '12px', 'margin': 0,
    'padding': '10px 14px', 'borderRadius': '6px',
    'backgroundColor': '#f5f5f5',
    'border': '1px solid #ddd',
    'whiteSpace': 'pre-wrap',
    'maxHeight': '150px',
    'overflow': 'auto',
}

component = html.Div([
    # --- 1. expansionTrigger="content" (default) ---
    html.Div([
        html.H3('1. Expansion Trigger: "content" (default)'),
        html.P("Click anywhere on the item row to expand/collapse.", style={'color': '#666'}),
        TreeView(
            id="tree-exp-content",
            items=DEEP_TREE,
            expansionTrigger="content",
        ),
    ], style=section_style),

    # --- 2. expansionTrigger="iconContainer" ---
    html.Div([
        html.H3('2. Expansion Trigger: "iconContainer"'),
        html.P("Only clicking the expand/collapse icon toggles the node.", style={'color': '#666'}),
        TreeView(
            id="tree-exp-icon",
            items=DEEP_TREE,
            expansionTrigger="iconContainer",
        ),
    ], style=section_style),

    # --- 3. Controlled expansion ---
    html.Div([
        html.H3("3. Controlled Expansion"),
        html.P("Use buttons to expand all or collapse all programmatically.", style={'color': '#666'}),
        html.Div([
            html.Button("Expand All", id="tree-exp-btn-all",
                        style={'marginRight': '8px', 'padding': '6px 12px'}),
            html.Button("Collapse All", id="tree-exp-btn-none",
                        style={'marginRight': '8px', 'padding': '6px 12px'}),
            html.Button("Expand Root Only", id="tree-exp-btn-root",
                        style={'padding': '6px 12px'}),
        ], style={'marginBottom': '10px'}),
        TreeView(
            id="tree-exp-controlled",
            items=DEEP_TREE,
            expandedItems=[],
        ),
        html.P("Expanded items:", style={'marginTop': '10px', 'fontSize': '13px', 'color': '#666'}),
        html.Pre(id="tree-exp-controlled-out", children="[]", style=output_style),
    ], style=section_style),

    # --- 4. Track expansion changes ---
    html.Div([
        html.H3("4. Track Expansion Changes"),
        html.P("expandedItems output updates whenever nodes are toggled.", style={'color': '#666'}),
        TreeView(
            id="tree-exp-track",
            items=DEEP_TREE,
            defaultExpandedItems=["root-a"],
        ),
        html.P("Currently expanded:", style={'marginTop': '10px', 'fontSize': '13px', 'color': '#666'}),
        html.Pre(id="tree-exp-track-out", children='["root-a"]', style=output_style),
    ], style=section_style),
])


@callback(
    Output("tree-exp-controlled", "expandedItems"),
    Output("tree-exp-controlled-out", "children"),
    Input("tree-exp-btn-all", "n_clicks"),
    Input("tree-exp-btn-none", "n_clicks"),
    Input("tree-exp-btn-root", "n_clicks"),
    Input("tree-exp-controlled", "expandedItems"),
    prevent_initial_call=True,
)
def controlled_expand(all_clicks, none_clicks, root_clicks, current):
    from dash import ctx
    trigger = ctx.triggered_id
    if trigger == "tree-exp-btn-all":
        items = ALL_PARENT_IDS
    elif trigger == "tree-exp-btn-none":
        items = []
    elif trigger == "tree-exp-btn-root":
        items = ["root-a", "root-b", "root-c"]
    else:
        items = current or []
    return items, json.dumps(items, indent=2)


@callback(
    Output("tree-exp-track-out", "children"),
    Input("tree-exp-track", "expandedItems"),
    prevent_initial_call=True,
)
def track_expansion(expanded):
    return json.dumps(expanded, indent=2) if expanded else "[]"

:defaultExpanded: false :withExpandedButton: true


Source: /tree-expansion

Note for AI agents: This is the static, prerendered view of an interactive Dash application served because we detected a non-JS user agent. Full prose docs: