Single-tier app#

A flat sidebar of top-level destinations — the everyday “dashboard” app. Each sidebar item is an authored page; selecting it shows that page’s content. With a single set of pages, no workspace rail appears.

Single-tier dashboard app — light theme Single-tier dashboard app — dark theme

How it works#

add_page(key, *, text, icon) registers a sidebar item and its content page together, and returns a context manager — widgets created inside the with block are parented to that page. add_footer_page() pins an item (Settings, Account) to the bottom of the sidebar. navigate(key) selects the starting page.

with shell.add_page("overview", text="Overview", icon="speedometer2"):
    bs.Label("Overview", font="heading-lg")
shell.navigate("overview")

Example#

 1"""Single-tier app — a flat list of top-level destinations (an analytics dashboard).
 2
 3Each ``add_page`` registers a sidebar item and its content together; the first
 4``navigate`` picks the starting page. With one set of pages no rail appears — this
 5is the everyday "sidebar app" shape.
 6"""
 7import bootstack as bs
 8
 9with bs.AppShell(title="Acme Analytics", size=(900, 580)) as shell:
10    shell.commandbar.add_label("Acme Analytics", font="heading-md")
11    shell.commandbar.add_spacer()
12    shell.commandbar.add_button(icon="circle-half", on_click=bs.toggle_theme)
13
14    with shell.add_page("overview", text="Overview", icon="speedometer2"):
15        with bs.VStack(fill="both", expand=True, anchor_items="w", gap=12, padding=20):
16            bs.Label("Overview", font="heading-lg")
17            with bs.Grid(columns=3, gap=12, fill="x", sticky_items="ew"):
18                for label, value in (("Revenue", "$48.2k"), ("Orders", "1,204"), ("Visitors", "18.9k")):
19                    with bs.Card(padding=16, gap=4):
20                        bs.Label(label, font="caption")
21                        bs.Label(value, font="heading-md")
22
23    with shell.add_page("reports", text="Reports", icon="bar-chart"):
24        with bs.VStack(fill="both", expand=True, anchor_items="w", gap=8, padding=20):
25            bs.Label("Reports", font="heading-lg")
26            bs.Label("Build and schedule reports.")
27
28    with shell.add_page("customers", text="Customers", icon="people"):
29        with bs.VStack(fill="both", expand=True, anchor_items="w", gap=8, padding=20):
30            bs.Label("Customers", font="heading-lg")
31            bs.Label("1,204 active accounts.")
32
33    with shell.add_footer_page("settings", text="Settings", icon="gear"):
34        with bs.VStack(fill="both", expand=True, anchor_items="w", gap=8, padding=20):
35            bs.Label("Settings", font="heading-lg")
36
37    shell.navigate("overview")
38
39shell.run()

When to use#

Reach for the single-tier app when you have a handful of independent destinations and no need to sub-group them. If the destinations fall into clear categories, add section labels — see Grouped sidebar. If the sidebar is really a list of records (messages, devices), use Master–detail (list) instead. If the app has several distinct areas each with their own sidebar, give each a workspace — see Workspaces (rail).