Multi page app Navbar links with URL prefix (base_pathname) not generating

I have a multi page app structured like this:

|-- src
|   |-- components
|   |   |-- __init__.py
|   |   |-- navbar.py
|   |-- pages
|   |   |-- __init__.py
|   |   |-- home.py
|   |-- app.py

In navbar.py I’m trying to create the link to every page dynamically like so (as shown in the example here https://github.com/AnnMarieW/dash-multi-page-app-demos/blob/main/multi_page_basics_pathname_prefix/app.py)

navbar = dbc.Navbar(
    dbc.Container(
        [
            dbc.NavbarToggler(id='navbar-toggler', n_clicks=0),
            dbc.Collapse(
                dbc.Nav(
                     [
                        dbc.NavItem(
                             dbc.NavLink(page['name'], href=page["relative_path"])
                        ) for page in dash.page_registry.values()
                     ],
                ),
                id='navbar-collapse',
                navbar=True
            ),
        ]
    ),
)

The navbar is included in the main app.py quite simply like

def serve_layout():
    return html.Div(
        [
            navbar,
            dbc.Container(
                dash.page_container,
                class_name='my-2'
            ),
        ]
    )

With this code the navbar does not show, probably because it cannot access dash.page_registry. I’ve tried encapsulating it into a function that returns navbar but this causes the layout to not load at all.

As workaround at the moment I’m creating the links manually, i.e.

navbar = dbc.Navbar(
    dbc.Container(
        [
            dbc.NavbarToggler(id='navbar-toggler', n_clicks=0),
            dbc.Collapse(
                dbc.Nav(
                    [
                        dbc.NavItem(
                            dbc.NavLink(
                                'Home',
                                href=URL_BASE_PATHNAME
                            )
                        ),
                        dbc.NavItem(
                            dbc.NavLink(
                                'Ensemble',
                                href=f'{URL_BASE_PATHNAME}ensemble/'
                            )
                        ),
                    ],
                ),
                id='navbar-collapse',
                navbar=True
            ),
        ]
    ),
)

Any idea how I could fix this?

I suspect that the problem is that you create the navbar earlier than you register the pages.

Please check it.

The pages are registered in their own module, but the import is done automatically by Dash, as I’m using use_pages=True in app.py.

The navbar is also defined in its own module and imported in the layout of the main app.py.

I’m not sure how I could change the order in which everything is created as it is handled automatically by Dash in this case.
Am I wrong?

What happens if you change the directory from components to utils?

Where are you importing the file for the navbar?

The source code is here

I do already have a utils folder with some common modules.

The only place where navbar is imported is the main app.py with

from components import navbar

Hmm, try this:

def navbar():
    navbar = dbc.Navbar(
        dbc.Container(
            [
                dbc.NavbarToggler(id='navbar-toggler', n_clicks=0),
                dbc.Collapse(
                    dbc.Nav(
                         [
                            dbc.NavItem(
                                 dbc.NavLink(page['name'], href=page["relative_path"])
                            ) for page in dash.page_registry.values()
                         ],
                    ),
                    id='navbar-collapse',
                    navbar=True
                ),
            ]
        ),
    )
    return navbar

And then when you want the navbar, replace navbar with navbar()

1 Like

You know what? I’m an idiot -.-

I did try to encapsulate it into a function but then forgot to call the function in app.py, so it is indeed working :slight_smile:

I Just had to modify page['name'] with page['title'] because I’m setting the name to __name__ but for the rest it works flawlessly!

Thanks for pointing out the typo

2 Likes