Context menu — right-click actions¶
Source: examples/panels/wunderbaum/context_menu.py
Test: tests/panels/wunderbaum/examples/test_context_menu.py
A tree-only Wunderbaum with a built-in context menu. Right-click a node to add a child, rename, or delete it — all handled by a single event callback that manipulates the tree via the Python API.
The code¶
import panel as pn
from panelini.panels.wunderbaum import Wunderbaum
pn.extension()
source = [
{
"title": "Project",
"key": "project",
"icon": "bi bi-folder-fill",
"expanded": True,
"children": [
{"title": "src", "key": "src", "icon": "bi bi-folder-fill", "children": [...]},
{"title": "README.md", "key": "readme", "icon": "bi bi-file-earmark-text"},
],
},
]
status = pn.pane.Markdown("**Right-click** a node to open the context menu.")
counter = {"value": 0}
def on_tree_event(event_name: str, event_params: dict) -> None:
if event_name == "contextmenu":
action = event_params.get("action", "")
key = event_params.get("key", "")
title = event_params.get("title", "")
if action == "add_child":
counter["value"] += 1
tree.add_node(key, {"title": f"New Node {counter['value']}", "key": f"new_{counter['value']}"})
tree.expand_node(key, True)
status.object = f"**Added** child to `{title}`"
elif action == "rename":
tree.rename_node(key, f"Renamed_{key}")
elif action == "delete":
tree.remove_node(key)
elif event_name == "activate":
status.object = f"**Activated:** {event_params.get('title', '')}"
tree = Wunderbaum(
source=source,
context_menu_items=[
{"id": "add_child", "label": "Add Child", "icon": "bi bi-plus-circle"},
{"id": "rename", "label": "Rename", "icon": "bi bi-pencil"},
{"id": "delete", "label": "Delete", "icon": "bi bi-trash"},
],
tree_event_callback=on_tree_event,
)
Key points:
context_menu_itemsdeclares the menu entries. Eachidbecomes theactionstring delivered to the callback.tree_event_callbackreceives(event_name, event_params)for every tree event. Filter onevent_name == "contextmenu"and dispatch onevent_params["action"].The callback drives the tree through the Python API:
add_node,rename_node,remove_node,expand_node.
How the test exercises it¶
The test serves the app and asserts the tree renders with rows. Note that the sibling Virtual filesystem — the full demo test marks its right-click assertion xfail — dispatching a real contextmenu event through the shadow DOM is unreliable under Playwright — so this example is verified for render and the callback logic is covered by the Python-API paths elsewhere.
See also¶
Virtual filesystem — the full demo — context menu plus DnD, rename, and file drop
Incremental updates — build a tree step by step — the same manipulation API, driven by buttons