Multipage Dash App using tabs instead of navbar

I have a multipage dash app. each page has its own python file (i.e page1.py, page2.py etc.).

On my app.py i have created a navbar which will have the path for each page and then i call dl.plugins.page_container to get all the pages.

This it the code:

# Initialize application
app_flask = flask.Flask(__name__)
server = app_flask
server.route("/application/")
app = dash.Dash(__name__,
                routes_pathname_prefix="/application/",
                plugins=[dl.plugins.pages])
server = app.server

# Create navbar
# Define navigation items
nav_items = [
    ("Page1", "page-1"),
    ("Page2", "page-2"),
]

# Create navbar items
navbar_items = [
    html.Div([
        dbc.Row(
            dbc.NavItem(
                dbc.NavLink(
                    label,
                    href=href,
                )
            )
        )
    ])
    for label, href in nav_items
]

# Assemble Navbar
navbar = dbc.Navbar(
    dbc.Container(
        [
            html.A(
                dbc.Row(
                    [
                        dbc.Col(html.Img(src=logo, height="50px")),
                    ],
                    align="center",
                    className="g-0",
                ),
            ),
            *navbar_items,
        ],
        fluid=True
    ),
)

# Define app layout
app.layout = dbc.Container([navbar, dl.plugins.page_container], fluid=True)

This works as expected with navbar. However i want to instead of using the Navbar to use dcc.Tabs. I cannot get it to work.

Can someone please guide me with how should i update my code so that it works the same as now however instead of navbar use dcc Tabs.

Hello @GabrielBKaram,

It is possible to have the tabs hooked up to the pathname as an output.

Basically, you listen to the value as an input and send it to the pathname as an output.

Hi @GabrielBKaram

It seems to me like you’re using an old approach for building a multi-page app, which I cannot follow but I have used the officially endorsed way and came up with the below. It’s still not perfect since the tabs component also refreshes with the page, even though I managed to keep the tab choice persistent after refresh

from dash import dash, html, dcc, callback, Input, Output

app = dash.Dash(
    __name__, use_pages=True, suppress_callback_exceptions=True,
)

tabs = dcc.Tabs(id="tabs", value='tab-0', children=[
        dcc.Tab(label='Home', value='tab-0'),
        dcc.Tab(label='Page1', value='tab-1'),
        dcc.Tab(label='Page2', value='tab-2')
    ],
                persistence_type='session',
                persistence=True)

app.layout = html.Div(
    [
    tabs,
    dcc.Location(id="url"),
    dash.page_container
    ]
)

@callback(Output('url', 'pathname'),
          Input('tabs', 'value'),
          prevent_initial_call=True)
def route(tab_value):
    if tab_value is not None:
        if tab_value == 'tab-0':
            return '/'
        if tab_value == 'tab-1':
            return 'page-1'
        if tab_value == 'tab-2':
            return 'page-2'


if __name__ == '__main__':
    app.run(debug=True, port=8053)

the above is the main app.py file, you would also need a ‘pages’ directory with 3 files as such:

page-1.py

import dash
from dash import html, dcc

dash.register_page(__name__, path="/page-1")

layout = html.Div(html.H1('PAGE 1'))

page-2.py

import dash
from dash import html, dcc


dash.register_page(__name__, path="/page-2")

layout = html.Div(html.H1('PAGE 2'))

home.py

import dash
from dash import html


dash.register_page(__name__, path="/")

layout = html.Div(html.H1('HOME PAGE'))

If you’re not familiar with it, you can read more about building multi-page apps here:

1 Like

Hi @mo.elauzei

Nice example! If you would like to be able to navigate each tab without refreshing the page (just like using a dcc.Link change your dcc.Location to:

dcc.Location(id="url", refresh="callback-nav"),

more info here:

1 Like

Thank you so much for the tip, @AnnMarieW ! this is super helpful to know.

worked great, thanks a lot @mo.elauzei