Thanks, @chriddyp and @AnnMarieW! The pages feature is an excellent addition and makes Dash even better!
I was wondering if it is possible to set up an app structure that allows multiple sub pages per page. The idea is to navigate the pages using a navigation bar at the top, and to add a second navigation bar whenever a page has sub pages. I came up with the following app structure and would like to ask whether you think this is a reasonable approach. For each of the pages, I have a folder containing page-specific stuff: layout, callbacks etc. In my example, page 2 has sub pages:
-- pages
|-- home
|-- home.py
|-- page_1
|-- page_1.py
|-- page_2
|-- sub_item_1
|-- sub_item_1.py
|-- sub_item_2
|-- sub_item_2.py
|-- submenu.py
|-- page_2.py
|-- other pages...
|-- app.py
In principle, I got this to work with the following implementation, but I am not sure if this is the best approach and would appreciate any kind of feedback. I only add navigation links to the navigation bar at the top when āsubā is not a sub string of the āmoduleā value of a page.
app.py:
import dash
import dash_labs as dl
import dash_bootstrap_components as dbc
from dash import html, Input, Output, State
app = dash.Dash( __name__, plugins=[dl.plugins.pages], external_stylesheets=[dbc.themes.BOOTSTRAP])
navbar = dbc.Navbar(
dbc.Container([
html.A(dbc.Row(
dbc.Col(dbc.NavbarBrand("MyApp", className="ms-2")),
align="center",
className="g-0",
),
href="/",
style={"textDecoration": "none"},
),
dbc.Row([
dbc.NavbarToggler(id="navbar-toggler"),
dbc.Collapse(
dbc.Nav([
dbc.NavItem(dbc.NavLink(page['name'], href=page['path'], active="exact")) for page in dash.page_registry.values() if page["module"] != "pages.not_found_404" and "sub" not in page["module"]
],
className="w-100",
),
id="navbar-collapse",
is_open=False,
navbar=True,
),
],
className="flex-grow-1",
),
],
fluid=True,
),
dark=True,
color="dark",
fixed="top",
sticky=True
)
app.layout = html.Div([navbar, dl.plugins.page_container])
@app.callback(
Output("navbar-collapse", "is_open"),
[Input("navbar-toggler", "n_clicks")],
[State("navbar-collapse", "is_open")],
)
def toggle_navbar_collapse(n, is_open):
if n:
return not is_open
return is_open
if __name__ == "__main__":
app.run_server(debug=True)
home.py:
import dash
from dash import html
import dash_bootstrap_components as dbc
dash.register_page(__name__, path="/", order=1)
content = [html.H2("Home")]
layout = html.Div([
dbc.Row(
dbc.Col(content, width={"size": 8, "offset": 1}),
align="center"
)
])
page_2.py:
import dash
from dash import dcc, html
from .submenu import sidebar
dash.register_page(__name__, path="/page_2", order=2)
content = html.Div([html.H2("Page 2")])
layout = html.Div([sidebar, content])
Creating the submenu automatically from the page registry does not work, so I am creating it manually. I assume, page 2 is not fully registered here, but creating it in app.py and importing it from there is not possible because it would be a circular import.
submenu.py:
import dash_bootstrap_components as dbc
from dash import html
sidebar = html.Div([
dbc.Nav([ # this works
dbc.NavLink("Sub Item 1", href="/page_2/item_1", active="partial"),
dbc.NavLink("Sub Item 2", href="/page_2/item_2", active="partial")
], vertical=True, pills=True),
# dbc.Nav([ # this does not work
# dbc.NavLink(page['name'], href=page['path'], active="exact") for page in dash.page_registry.values() if page["module"] != "pages.not_found_404" and "page_2.sub" in page["module"]
# ], vertical=True, pills=True)
], style={"position": "fixed", "padding": "1rem 1rem", "background-color": "#f8f9fa", "height": "100vh"})
sub_item_1.py:
import dash
from dash import html
from ..submenu import sidebar
dash.register_page(__name__, path="/page_2/item_1", order=1)
content = html.Div([html.H2("Page 2 - Item 1")])
layout = html.Div([sidebar, content])
sub_item_2.py:
import dash
from dash import html
from ..submenu import sidebar
dash.register_page(__name__, path="/page_2/item_2", order=1)
content = html.Div([html.H2("Page 2 - Item 2")])
layout = html.Div([sidebar, content])
With this setup, the āactiveā style of the dbc.NavLinks in the navigation bar at the top does not work any more. Any ideas on how to use this feature? Any feedback would be highly appreciated!