Examples

The examples below demonstrate the key features of shiny-treeview, a TreeView UI component for Shiny for Python backed by Material UI.

Each example is written using the concise Shiny Express API. The more powerful Shiny Core API is also supported. The examples run in your web browser using Shinylive, which means you can quickly test ideas by editing the source code and re-running the app.

Basic usage

Start with a simple hierarchical tree structure. Click on any item to select it.

#| '!! shinylive warning !!': |
#|   shinylive does not work in self-contained HTML documents.
#|   Please set `embed-resources: false` in your metadata.
#| standalone: true
#| components: [editor, viewer]
#| layout: horizontal
#| viewerHeight: 300

## file: app.py
from shiny.express import input, render
from shiny_treeview import input_treeview
from data1 import tree_data

input_treeview("my_tree", tree_data)


@render.text
def value():
    return f"Selected: {input.my_tree()}"


## file: data1.py
from shiny_treeview import TreeItem

tree_data = [
    TreeItem(
        "docs",
        "๐Ÿ“ Documents",
        children=[
            TreeItem("report", "๐Ÿ“„ Report.pdf"),
            TreeItem("slides", "๐Ÿ“„ Slides.pptx"),
        ],
    ),
    TreeItem("readme", "โ„น๏ธ README.md"),
]


## file: requirements.txt
shiny
shiny-treeview

Selection modes

With multiple selection enabled, hold Ctrl/Cmd or Shift while clicking to select multiple items. Try toggling multiple selection below by editing the multiple argument, to see how it impacts user interactions.

#| '!! shinylive warning !!': |
#|   shinylive does not work in self-contained HTML documents.
#|   Please set `embed-resources: false` in your metadata.
#| standalone: true
#| components: [editor, viewer]
#| layout: horizontal
#| viewerHeight: 500

## file: app.py
from shiny.express import input, render
from shiny_treeview import input_treeview
from data2 import tree_data

input_treeview(
    "my_tree",
    tree_data,
    multiple=True,
)


@render.text
def multi_value():
    selected = input.my_tree()
    if isinstance(selected, tuple):
        return f"Selected: {', '.join(selected)}"
    else:
        return f"Selected: {selected}"


## file: data2.py
from shiny_treeview import TreeItem

tree_data = [
    TreeItem(
        id="movies",
        label="๐ŸŽฌ Movies",
        children=[
            TreeItem(
                id="action",
                label="๐Ÿ’ฅ Action",
                children=[
                    TreeItem(id="diehard", label="Die Hard"),
                    TreeItem(id="madmax", label="Mad Max: Fury Road"),
                ],
            ),
            TreeItem(
                id="comedy",
                label="๐Ÿ˜‚ Comedy",
                children=[
                    TreeItem(id="groundhog", label="Groundhog Day"),
                    TreeItem(id="princess", label="The Princess Bride"),
                ],
            ),
        ],
    ),
    TreeItem(
        id="music",
        label="๐ŸŽต Music",
        children=[
            TreeItem(
                id="rock",
                label="๐ŸŽธ Rock",
                children=[
                    TreeItem(id="queen", label="Queen - Bohemian Rhapsody"),
                    TreeItem(id="beatles", label="The Beatles - Hey Jude"),
                ],
            ),
            TreeItem(
                id="jazz",
                label="๐ŸŽบ Jazz",
                children=[
                    TreeItem(id="miles", label="Miles Davis - Kind of Blue"),
                    TreeItem(id="coltrane", label="John Coltrane - A Love Supreme"),
                ],
            ),
        ],
    ),
    TreeItem(
        id="podcasts",
        label="๐ŸŽ™๏ธ Podcasts",
        children=[
            TreeItem(id="tech-podcast", label="Tech Talk Weekly"),
        ],
    ),
    TreeItem(id="home-video", label="๐Ÿ“น Family Vacation 2023"),
]


## file: requirements.txt
shiny
shiny-treeview

Checkbox selection

When checkboxes are enabled, a tree item is selected by clicking on the checkbox element. This decouples the select action from the expand/contract action. Now multiple tree items can be selected without holding down a key.

#| '!! shinylive warning !!': |
#|   shinylive does not work in self-contained HTML documents.
#|   Please set `embed-resources: false` in your metadata.
#| standalone: true
#| components: [editor, viewer]
#| layout: horizontal
#| viewerHeight: 500

## file: app.py
from shiny.express import input, render
from shiny_treeview import input_treeview
from data3 import tree_data


input_treeview(
    "my_tree",
    tree_data,
    multiple=True,
    checkbox=True,
)


@render.text
def value():
    return f"Selected: {input.my_tree()}"


## file: data3.py
from shiny_treeview import TreeItem

tree_data = [
    TreeItem(
        id="groceries",
        label="๐Ÿ›’ Groceries",
        children=[
            TreeItem(
                id="produce",
                label="๐Ÿฅฌ Produce",
                children=[
                    TreeItem(id="bananas", label="๐ŸŒ Bananas"),
                    TreeItem(id="spinach", label="๐Ÿƒ Fresh Spinach"),
                    TreeItem(id="tomatoes", label="๐Ÿ… Cherry Tomatoes"),
                ],
            ),
            TreeItem(
                id="dairy",
                label="๐Ÿฅ› Dairy",
                children=[
                    TreeItem(id="milk", label="๐Ÿฅ› Whole Milk"),
                    TreeItem(id="cheese", label="๐Ÿง€ Cheddar Cheese"),
                    TreeItem(id="yogurt", label="๐Ÿฅ„ Greek Yogurt"),
                ],
            ),
        ],
    ),
    TreeItem(
        id="household",
        label="๐Ÿ  Household",
        children=[
            TreeItem(
                id="cleaning",
                label="๐Ÿงฝ Cleaning",
                children=[
                    TreeItem(id="detergent", label="๐Ÿงด Laundry Detergent"),
                    TreeItem(id="sponges", label="๐Ÿงฝ Kitchen Sponges"),
                ],
            ),
        ],
    ),
    TreeItem(id="batteries", label="๐Ÿ”‹ AA Batteries"),
    TreeItem(id="gift", label="๐ŸŽ Birthday Gift Wrap"),
]


## file: requirements.txt
shiny
shiny-treeview

Working with flat data

Transform flat data (like CSV or database results) into hierarchical trees using the stratify helper functions. If the hierarchy structure is expressed through a parent ID field, then use stratify_by_parent().

#| '!! shinylive warning !!': |
#|   shinylive does not work in self-contained HTML documents.
#|   Please set `embed-resources: false` in your metadata.
#| standalone: true
#| components: [editor, viewer]
#| layout: horizontal
#| viewerHeight: 500

## file: app.py
from shiny.express import input, render
from shiny_treeview import input_treeview, stratify_by_parent, TreeItem
from data4 import read_data


employees_db = read_data()

employees, manager_ids = [], []
for row in employees_db.values():
    label = "{icon} {name} ({title})".format(**row)
    employees.append(TreeItem(id=row["employee_id"], label=label))
    manager_ids.append(row["manager_id"] if row["manager_id"] else None)

# Convert flat data into hierarchical tree
tree_data = stratify_by_parent(employees, manager_ids)
input_treeview("org_tree", tree_data, selected="7")


@render.text
def selected_employee():
    selected = input.org_tree()
    if not selected:
        return "No employee selected"
    return employees_db[selected]["name"]


## file: data4.py
import csv
from io import StringIO

# Sample CSV data representing an organizational chart
# In practice, this could be loaded from a file or database
csv_data = """employee_id,name,title,manager_id
1,Sarah Chen,CEO,
2,Alex Rodriguez,CTO,1
3,Maya Patel,CFO,1
4,Jordan Kim,Senior Engineer,2
5,Riley Thompson,Engineer,2
6,Casey Davis,UX Designer,2
7,Sam Wilson,Analyst,3
8,Taylor Brown,Accountant,3"""

role_icons = {
    "CEO": "๐Ÿ‘‘",
    "CTO": "๐Ÿ’ป",
    "CFO": "๐Ÿ’ฐ",
    "Senior Engineer": "๐Ÿ”ง",
    "Engineer": "๐Ÿ”ง",
    "UX Designer": "๐ŸŽจ",
    "Analyst": "๐Ÿ“Š",
    "Accountant": "๐Ÿ“ˆ",
}


def read_data() -> dict[str, dict]:
    """Parse CSV data and return list of employee records with icons."""
    reader = csv.DictReader(StringIO(csv_data))

    rows = {}
    for row in reader:
        row["icon"] = role_icons.get(row["title"], "๐Ÿ‘ค")
        rows[row["employee_id"]] = row

    return rows


## file: requirements.txt
shiny
shiny-treeview