Notebook
Consider TabView
Notebook is included as a wrapper around the native bs.Notebook widget.
For new projects, consider using TabView instead, which offers
a more modern appearance, closable tabs, dynamic tab creation, and better
integration with bootstack's design system.
Notebook is a tabbed view container that shows one page at a time and lets users switch views by clicking tabs.
bootstack's Notebook extends bs.Notebook with:
-
key-based tab references (stable, human-friendly)
-
optional auto-generated keys
-
helpers for hide/show/remove while keeping the tab registry consistent
-
enriched tab lifecycle events that describe what changed and why
Quick start
Create a notebook and add tabs using add():
import bootstack as bs
app = bs.App()
nb = bs.Notebook(app, accent="primary")
nb.pack(fill="both", expand=True, padx=20, pady=20)
# add() creates a Frame and returns it
home = nb.add(text="Home", key="home")
settings = nb.add(text="Settings", key="settings")
bs.Label(home, text="Home content").pack(anchor="w", padx=10, pady=10)
bs.Label(settings, text="Settings content").pack(anchor="w", padx=10, pady=10)
app.mainloop()
You can also add an existing widget as a tab:
page = bs.Frame(nb, padding=10)
bs.Label(page, text="I was created outside the notebook").pack(anchor="w")
nb.add(page, key="external", text="External")
When to use
Use Notebook when:
-
you have multiple related views sharing the same window area
-
switching views should be fast and non-destructive
-
you want a familiar desktop "tabs" model
Consider a different control when:
-
the workflow is sequential (wizard/flow) - use PageStack instead
-
back/forward history matters - use PageStack instead
-
you have many sections that don't fit well as tabs - consider a side navigation pattern
Appearance
Styling
Apply an accent to change the tab accent color:
nb = bs.Notebook(app, accent="primary")
Design System
See Colors & Themes for available color values.
Examples and patterns
Tab references
Most notebook APIs accept a "tab reference" that can be:
-
key (
str) - recommended (stable) -
index (
int) - 0-based position -
widget - the tab's content widget
nb.select("settings") # by key
nb.select(0) # by index
nb.select(settings) # by widget
Prefer keys
Indices change when tabs are inserted, removed, or reordered. Keys remain stable.
Creating tabs
Use add() without a child to create a Frame automatically:
page = nb.add(text="Logs", key="logs")
bs.Label(page, text="Log content").pack()
Use insert() to add at a specific position:
page = nb.insert(0, text="Start", key="start")
Frame options (padding, color, etc.) can be passed directly:
page = nb.add(text="Settings", key="settings", padding=10, accent="primary")
Localized tab labels
Notebook supports translation-aware tab text (tokens retranslate on locale changes). You can also provide formatting args:
nb.add(page, key="recent", text="tabs.recent", fmtargs=("Today",))
Hide vs remove
Hide a tab without forgetting it:
nb.hide("settings")
Remove a tab and clean its registry entry:
nb.remove("settings")
Hide vs remove
Use hide(...) for temporary visibility (feature flags, permissions).
Use remove(...) when the tab should be forgotten entirely.
Disable a tab
nb.tab("settings", state="disabled")
Reorder tabs
Use insert(...) to move a widget to a new index. Keys remain stable even if indices change.
Events
Notebook emits enriched lifecycle events:
-
<<NotebookTabChanged>> -
<<NotebookTabActivated>> -
<<NotebookTabDeactivated>>
Use the helper methods to subscribe/unsubscribe:
def on_changed(event):
data = getattr(event, "data", None) or {}
print("current:", data.get("current"))
print("previous:", data.get("previous"))
print("reason:", data.get("reason"))
print("via:", data.get("via"))
funcid = nb.on_tab_changed(on_changed)
# nb.off_tab_changed(funcid)
Event payload
For on_tab_changed(...), event.data includes:
-
current:{index, key, label}orNone -
previous:{index, key, label}orNone -
reason:"user" | "api" | "hide" | "forget" | "reorder" | "unknown" -
via:"click" | "key" | "programmatic" | "unknown"
Track navigation state
Use reason and via to distinguish user clicks from programmatic navigation (wizards, validation redirects).
Behavior
UX guidance
-
Keep tab labels short and scannable
-
Avoid too many tabs in one notebook (consider grouping or alternative navigation)
-
Use
hide(...)for permission-based tabs -
Use
on_tab_changed(...)to persist the last selected tab between sessions
Additional resources
Related widgets
-
PageStack - stacked views with history (wizards/flows)
-
Frame - common tab page container
-
PanedWindow - split layouts often paired with view switching