# Dash Pages - Multi-Page App with Subtabs using dbc.NavLinks

**URL:** <https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312>\
**Category:** Dash Python\
**Created:** [February 5, 2023, 8:08pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312 "2023-02-05T20:08:46Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![etonblue](https://avatars.discourse-cdn.com/v4/letter/e/bb73d2/32.png) [@etonblue](https://community.plotly.com/u/etonblue)\
**Post date:** [February 5, 2023, 8:08pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/1 "2023-02-05T20:08:46Z")

</div>

I have an app I’ve been working on for a while. Prior to the release of Pages, it was structured as a multi-page app using the ‘old way’ using dcc.Tabs. More specifically, ‘app.py’ creates app instance and imports all of the other pages (e.g. hello.py, world.py, etc), all of which had a ‘layout’ variable. I then used a callback to determine which layout to display. E.g. (in app.py):

```auto
@app.callback(Output('tabs-content', 'children'),
                [Input('tabs', 'value')],
)
def render_tab(tab):

    if tab == 'tab-1':
        return hello.layout
    elif tab == 'tab-2':
       return world.layout

```

The app.py layout is composed of the navigation and a div for the content:

```auto
app.layout = html.Div(
                [
                   html.Div(
                        [
                            dcc.Tabs(
                                id='tabs',
                                value='tab-1',
                                children=[
                                    dcc.Tab(label='Hello', value='tab-1'),
                                    dcc.Tab(label='World', value='tab-2')
                                ],
                            ),
                        ],
                    html.Div(id='tabs-content'),
    ])

```

This all worked fine. However, I wanted to refactor the app to use the new Pages functionality.

So I removed the individual page imports and added added ‘use\_pages=True’  
to app.py. I also added ‘dash.register\_page( **name** )’, changed @app.callback to @callback, and deleted the “if **name** == ‘ **main** ’: app.run\_server(debug=True)” line in each individual page.

However, I wasn’t quite sure how to integrate the dcc.Tabs functionality into Pages. For example, where does dash.page\_container go? And how should I modify my tab callback?

Right now my modified layout looks like this:

```auto
app.layout = html.Div(
                [
                   html.Div(
                        [
                            dcc.Tabs(
                                id='tabs',
                                value='tab-1',
                                children=[
                                    dcc.Tab(label='Hello', value='tab-1'),
                                    dcc.Tab(label='World', value='tab-2')
                                ],
                            ),
                        ],
                    html.Div(id='tabs-content'),
                    dash.page_container,
    ])

```

and my modified Tab callback looks like this:

```auto
@app.callback(Output('tabs-content', 'children'),
                [Input('tabs', 'value')],
)
def render_tab(tab):

    if tab == 'tab-1':
        return dcc.Location(pathname=dash.page_registry['pages.hello']['path'], id="registry-hello")
    elif tab == 'tab-2':
       return dcc.Location(pathname=dash.page_registry['pages.world']['path'], id="registry-world")

```

But this does not work. On load, everything seems fine. the Navigation loads and the ‘hello’ page (tab 1) displays just fine. However, when I click on Tab 2 (world.py), it appears to load for a split second, but then the entire app updates and everything resets back to tab 1.

I tried moving dash.page\_container inside the ‘tab-content’ div, but that just resulted in no tab displaying. I am convinced (I hope) that this is an easy fix, but I’ve been looking for a couple of hours now and I cannot seem to figure it out.

Thanks for any help!

---

<div class="post-metadata">

**Author:** ![AIMPED](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/aimped/32/21758_2.png) [@AIMPED](https://community.plotly.com/u/AIMPED)\
**Post date:** [February 5, 2023, 8:24pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/2 "2023-02-05T20:24:11Z")

</div>

The page container is where your pages get rendered. Try commenting out your callback and everything related to the tabs

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [February 5, 2023, 9:33pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/3 "2023-02-05T21:33:17Z")

</div>

Hi @etonblue

Just to expand on @AIMPED’s answer, the callback logic required for URL routing is included with Pages, so you don’t need to included that in your app. When the url is updated, for example when a user clicks on a link, Pages will automatically render the layout for that page in the `dash.page_container`

The `dcc.Tab` component doesn’t work well with the Pages navigation (There is a way to update the url in a callback, but this isn’t the “easy” way) . Instead , you could use `dcc.Link` components and style them to look like tabs. Another solution is to use a `dbc.Nav` and `dbc.NavLink` components. You can find examples here: [Nav - dbc docs](https://dash-bootstrap-components.opensource.faculty.ai/docs/components/nav/#)

Here is an example of a nav component that is styled to look like tabs.

```auto

dbc.Nav(
    [
        dbc.NavLink(
            html.Div(page["name"], className="ms-2"),
            href=page["path"],
            active="exact",
        )
        for page in dash.page_registry.values()
    ],
    pills=True,    
)

```

---

<div class="post-metadata">

**Author:** ![etonblue](https://avatars.discourse-cdn.com/v4/letter/e/bb73d2/32.png) [@etonblue](https://community.plotly.com/u/etonblue)\
**Post date:** [February 6, 2023, 2:58pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/4 "2023-02-06T14:58:24Z")

</div>

Unfortunately my tab structure is a bit more involved. In the actual app, the Navigation area has five tabs, two of which have 3 subtabs. Each tab is a different page, e.g., tab1=page1, subtab2-1=page2, subtab 2-2=page 3, subtab 2-3=page 4, subtab 3=page 5, for a total of 9 separate pages. The layout:

```auto
[Tab1] [Tab2] [Tab3] [Tab4] [Tab5] <- always displayed
 [SubTab2-1][SubTab2-2][Subtab2-3] <- hidden unless one of two tabs with subtabs is selected
           [Tab Content]

```

This is easy to do with dcc.Tab and dcc.Tabs.

```auto
dcc.Tabs(
     value='tab-1',
     children=[
         dcc.Tab(label='Tab 1', value='tab-1'),
         dcc.Tab(label='Tab 2', value='tab-2', children=[
             dcc.Tabs(id='subtab2', value='subtab2-1', children=[
                 dcc.Tab(label='Subtab 2 - 1', value='subtab2-1'),
                 dcc.Tab(label='Subtab 2 - 2', value='subtab2-2')
             ])
         ]),
         dcc.Tab(label='Tab 3', value='tab-3'),
     ])

```

etc. etc.

I am not that familiar with dash bootstrap-components as I don’t use it anywhere else in my app, but I could not figure out how to easily re-create my ‘subtab’ layout using dbc.NavBar. I tried mixing and matching dbc.NavBar and dbc.Collapse and some other components, but found myself back in the same situation where I was trying to insert a specific url in a specific place. Am I missing some NavBar functionality? Or is this just a case where I have to choose between my layout or the Pages functionality?

---

<div class="post-metadata">

**Author:** ![jinnyzor](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/jinnyzor/32/21194_2.png) [@jinnyzor](https://community.plotly.com/u/jinnyzor)\
**Post date:** [February 6, 2023, 3:03pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/5 "2023-02-06T15:03:23Z")

</div>

Hello @etonblue,

Is it possible for you to record the way your interactions were in the old index version?

It might help us understand a little more about how your app was working.

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [February 6, 2023, 3:11pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/6 "2023-02-06T15:11:31Z")

</div>

You can make the sub tab part of the layout in the pages that have sub-tabs. You can find an example here:

> **[GitHub - AnnMarieW/dash-multi-page-app-demos: Minimal examples of multi-page...](https://github.com/AnnMarieW/dash-multi-page-app-demos#7-multi_page_layout_functions)**
>
> Minimal examples of multi-page apps using the pages feature in dash\>=2.5.1 - GitHub - AnnMarieW/dash-multi-page-app-demos: Minimal examples of multi-page apps using the pages feature in dash\>...

Also, if you prefer to use the tabs, it is still possible to use callbacks for navigation. You can find more examples in the [Navitation with Callbaks section](https://github.com/AnnMarieW/dash-multi-page-app-demos#navigation-in-a-callback) . The downside with this method currently is that it refreshes the page when you change the tabs. There is an open pull request to fix this, but it’s not been merged yet.

---

<div class="post-metadata">

**Author:** ![etonblue](https://avatars.discourse-cdn.com/v4/letter/e/bb73d2/32.png) [@etonblue](https://community.plotly.com/u/etonblue)\
**Post date:** [February 6, 2023, 4:43pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/7 "2023-02-06T16:43:56Z")

</div>

Okay, I think I can work with this! I have incorporated your example into my app and it is almost working (other than the layout that I will have to recreate). So my folder structure is:

```auto
project/
|-----app.py
|---- data/
|---- assets/
|---- pages/
        |---- page1.py
        |---- red-page2.py
        |---- red-page3.py
        |---- red-page4.py
        |---- page5.py
        |---- sub_nav.py

```

changes to app.py:

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

dbc.Nav(
    [
        dbc.NavLink(page['name'], href=page['path'])
            for page in dash.page_registry.values()
            if page.get('top_nav')
    ],
    pills=True,    
),

```

additions to the page files that I want displayed at the top level of the menu (page1.py, red-page2.py and page5.py):

```auto
from .sub_nav import subnav
dash.register_page( __name__ , top_nav=True)

```

additions to the pages that should be displayed only at the sub\_nav level (red-page2.py, red-page3.py, red-page4.py):

```auto
from .sub_nav import subnav
dash.register_page(__name_)

```

addition to the ‘layout’ of all pages in the pages folder:

```auto
html.Div(subnav()),

```

the sub\_nav.py file looks like this:

```auto
def subnav():
    return html.Div(
        dbc.Nav(
            [
                dbc.NavLink(
                    [
                        html.Div(page["name"], className="ms-2"),
                    ],
                    href=page["path"],
                    active="exact",
                )
                for page in dash.page_registry.values()
                if page["path"].startswith('/red')
                #for page in dash.page_registry.values()
                #if 'red' in page["path"]
            ],
            # vertical=False,
            pills=True,
            className="bg-light",
        )
    )

```

I have two problems.  
First, the last page meeting the sub\_nav condition (red-page4.py) doesn’t show up at all. It is set up exactly the same as the second page (red-page3.py).

Second, it appears as if the dash.page\_registry is incomplete when the subnav function is called for certain pages. So if I click on the red-page2 top\_nav link, I get a link to red-page2 in the sub\_nav menu. If I click on the red-page3 sub\_nav link, I get a link to red-page2 and red-page3 in the sub\_nav menu. What I want is for the sub\_nav menu to display all three pages matching the condition in the sub\_nav menu.

Any idea why these two things are happening?

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [February 6, 2023, 5:03pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/8 "2023-02-06T17:03:06Z")

</div>

To access `dash.page_registry` from within a file in the `pages` directory, you’ll need to use it within a function. You can see this in action in the example in the GitHub repo.

For more information about this, see the Dash Page Registry section of the docs:

> **[Multi-Page Apps and URL Support | Dash for Python Documentation | Plotly](https://dash.plotly.com/urls#dash-page-registry)**
>
> Dash provides two components (\`dcc.Link\` and \`dcc.Location\`) that allow you to easily make fast multipage apps using its own Single Page App (SPA) design pattern.

---

<div class="post-metadata">

**Author:** ![etonblue](https://avatars.discourse-cdn.com/v4/letter/e/bb73d2/32.png) [@etonblue](https://community.plotly.com/u/etonblue)\
**Post date:** [February 6, 2023, 6:01pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/9 "2023-02-06T18:01:38Z")

</div>

@AnnMarieW thank you for your patience.

I have been closely following the example you initially provided (which appears to be the same example in the Documentation page), which includes utilizing a function to access dash.page\_registry.

In my previous post, I have a file in the pages directory (sub\_nav.py) that contains a layout function subnav() that returns a NavLink object with all of the pages in dash.page\_registry that startwith (‘red’). The subnav() function is imported (from .sub\_nav import subnav) and called in the layout of each page.

As I described above, it sorta works, but seems to be missing pages depending on when subnav() is called.This is what I cannot seem to figure out.

For example, If I add your registry debugging code:

```auto
# --- debugging - print `dash.page_registry`
import json
registry = {a:{c:d for c, d in b.items() if c != 'layout'} for a, b in dash.page_registry.items()}
print(json.dumps(registry, indent=4))

```

to app.py or to the top-level of a page with sub-pages (e.g., red-page1.py), it shows all 9 pages in the dict.

However, if I add the debugging code to the sub\_nav function itself, it loads the dict 3 times (presumably once for each time the subnav() function appears in a page layout). The first dict has 5 pages (missing two of the subnav pages), the second dict has 6 pages (missing one of the subnav pages), and the third dict has 7 pages (all of the subnav pages, but missing the two last top\_nav pages).

So clearly, when the function is firing, dash.page\_registry is not complete despite the fact that I am using a function to access dash.page\_registry. Banging my head against my desk at this point. I should note that the only layout that is a function in my app is the one in sub\_nav.py.

---

<div class="post-metadata">

**Author:** ![etonblue](https://avatars.discourse-cdn.com/v4/letter/e/bb73d2/32.png) [@etonblue](https://community.plotly.com/u/etonblue)\
**Post date:** [February 6, 2023, 6:36pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/10 "2023-02-06T18:36:47Z")

</div>

After reading all 141 pages of the [“Introducing Dash Pages”](https://community.plotly.com/t/introducing-dash-pages-a-dash-2-x-feature-preview/57775/63) thread on this forum, I finally hit upon the solution (which was, of course, staring me in the face from the example), although I am not exactly sure ‘why’ it works.

All I had to do was change all of the layouts in each of my pages to functions. So changing:

```auto
layout = html.Div(
            [

```

to:

```auto
def layout():
    return html.Div(
           [

```

fixed my issue. Egg on my face, but this is actually in @AnnMarieW’s example: [“dash multi page app multi\_page\_layout\_functions”](https://github.com/AnnMarieW/dash-multi-page-app-demos/tree/main/multi_page_layout_functions), but I somehow missed it. I was focused on the sub\_nav function and not on the layouts.

So its fixed, but I am still not sure I understand why.

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [February 6, 2023, 8:57pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/11 "2023-02-06T20:57:43Z")

</div>

Glad you got this working! Making the layout a function is they key to making it work, so I’ll try to make it more clear in the example.

The reason it needs to be a function is that the `dash.page_registry` dict is built as each module in the pages folder is imported by Pages before the app starts. So `layout=`… is defined at the time the page is imported, and the `dash.page_registry` is not yet complete. When the layout is a function, it gets called when the app is running and you navigate to that page. At that time the `dash.page_registry` is complete, so it works 🎉

---

<div class="post-metadata">

**Author:** ![etonblue](https://avatars.discourse-cdn.com/v4/letter/e/bb73d2/32.png) [@etonblue](https://community.plotly.com/u/etonblue)\
**Post date:** [September 19, 2023, 2:26pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/12 "2023-09-19T14:26:25Z")

</div>

Well it’s been awhile, but I am back with another directly related question. As mentioned above, my layout is something like:

> [Tab1] [Tab2] [Tab3] ← always displayed  
> [SubTab2-1][SubTab2-2][Subtab2-3] ← hidden unless one of two tabs with subtabs is selected  
> [Tab Content]

Thanks to @AnnMarieW, I was able to get this to work by making a sub-tab function part of the layout in each of the pages with subtabs. However, this results in the name of the parent tab being repeated as the name of one of the subtabs. For example assume the following tabs, with the **Trucks** parent tab currently selected:

[Cars] [**Trucks**] [Planes]  
[**Trucks**][Dump Trucks][Garbage Trucks]  
[**Trucks Page**]

As you can see, the “page” Trucks appears as both a Tab and one of the Subtabs. But I do not want the parent page Trucks to display anything other than the subtabs and the first subtab page. So instead we would have:

[Cars] [**Trucks**] [Planes]  
[**Dump Trucks**][Garbage Trucks]  
[**Dump Trucks Page**]

Where the Trucks page acts as a container for the two sub-tabs and the first sub-tab (Dump Trucks) opens by default when Trucks is selected.

I’ve tried creating a dummy Truck page with a layout something like:

```
def layout():
return html.Div(
    [
        /* html.Div(id="hidden", style = {"display": "none"}), */
        html.Div(
            [
                html.Div(
                    [
                        html.Div(subnav_truck_types(), className="tabs"),
                    ],
                    className="bare-container--flex--center twelve columns",
                ),
            ],
            className="row",
        ),
    ],
    id="main-container",
)

```

where the subnav function looks like:

```
def subnav_truck_types():
return html.Div(
    dbc.Nav(
        [
            dbc.NavLink(
                page['name'],
                href=page['path'],
                className = 'tab',
                active='partial'
            )
            for page in dash.page_registry.values()
            if page["path"].startswith("/trucks/")
        ],
        className='sub-tabs',
        style={"marginTop": "-40px"}
    )
)

```

but I couldn’t quite figure out what the output would be to get the first subtab to automatically load. I could get the subtabs to show by adding a “hidden” div, but that clearly isn’t the answer because the subtab pages would only show if they were clicked.

Two questions:

1. How do I structure this so the first sub-tab page ([Dump Trucks]) displays as default when the parent [Truck] tab is selected; and
2. where the layout switches to the second sub-tab page ([Garbage Trucks]) when selected?

I am positive that I am just missing something easy and I am looking forward to @AnnMarieW’s one line solution. 🙂

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [September 19, 2023, 3:16pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/13 "2023-09-19T15:16:43Z")

</div>

> [@etonblue](#):
>
> I am positive that I am just missing something easy and I am looking forward to @AnnMarieW’s one line solution. 🙂

Haha I have a suggestion that’s close to a one-line solution (I hope it works for you 🙂 )

You can add arbitrary entries into the `dash.page_registry` dict to make it easier to loop through to create things like sub menus. For example in the Trucks sup-pages, you can add:

```auto
dash.register_page(__name_, sub_menu="trucks")

```

Then when you loop through to create the sub menu, it would look like:

```auto

    dbc.Nav(
        [
            dbc.NavLink(
                page['name'],
                href=page['path'],
                className = 'tab',
                active='partial'
            )
            for page in dash.page_registry.values()
            if page["sub_menu"] == "trucks"
        ]
       

```

You can see an example [multi-page-app-demos](https://github.com/AnnMarieW/dash-multi-page-app-demos). See example #7. The links in the top nav bar are created this way.

If this doesn’t work, I may need to see a little more code. If you could post a minimal example it would help.

---

<div class="post-metadata">

**Author:** ![etonblue](https://avatars.discourse-cdn.com/v4/letter/e/bb73d2/32.png) [@etonblue](https://community.plotly.com/u/etonblue)\
**Post date:** [September 19, 2023, 3:56pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/14 "2023-09-19T15:56:42Z")

</div>

Thanks for the quick reply! Unfortunately, its not quite what I am trying to do. My directory structure includes a subdirectory in the pages folder (/pages/trucks/). Inside that folder are two “pages”: dumptruck.py and garbagetruck.py. Using:

```
if page["path"].startswith("/trucks/")

```

in my sub\_nav function works just fine to display the subtabs. You suggested using an arbitrary entry:

```
if page["sub_menu"] == "trucks"

```

Which also works just fine to display the sub-tabs when the parent tab is selected (although to get the arbitrary entry to work, I had to add the variable/value pair to **each** page (.e.g, sub\_menu = “trucks” for the two truck subtabs and sub\_menu = “None” to all of the other pages). Otherwise I kept getting key (“sub\_menu”) not found errors).

However, neither my solution nor your proposed solution auto selects the first subtab and displays the first subtab page in the container.

Actually, your pages example #7 is a perfect MRE for the problem. The behavior of example #7 is exactly what I have now. That is, when you click on the “Topics” navbar link, three subtabs appear: “Topics” (again), “Topic 2”, and “Topic 3”.

What I want is a version of example #7 where only “Topic 2” and “Topic 3” appear as subtabs when “Topics” is selected, where Topic 2 (the first sub-page) is automatically selected and displayed in the container, and where when I click on Topic 3, Topic 3 replaces Topic 2 in the container.

Is there a way to delineate a specific page as “active” in a layout?

---

<div class="post-metadata">

**Author:** ![jinnyzor](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/jinnyzor/32/21194_2.png) [@jinnyzor](https://community.plotly.com/u/jinnyzor)\
**Post date:** [September 19, 2023, 4:29pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/15 "2023-09-19T16:29:06Z")

</div>

Hello @etonblue,

Technically, yes, you could do this.

When registering a page, you can define anything that you want to, as long as the name doesnt interfere.

Here is a callback designed to redirect to the first child:

```auto
import dash
from dash import Input, Output, State

import dash_bootstrap_components as dbc

app = dash.Dash(
    __name__ ,
    use_pages=True,
    external_stylesheets=[dbc.themes.BOOTSTRAP],
)

navbar = dbc.NavbarSimple(
    dbc.Nav(
        [
            dbc.NavLink(page["name"], href=page["path"])
            for page in dash.page_registry.values()
            if page.get("top_nav")
        ],
    ),
    brand="Multi Page App Demo",
    color="primary",
    dark=True,
    className="mb-2",
)

app.layout = dbc.Container(
    [navbar, dash.page_container],
    fluid=True,
)

@app.callback(
    Output('_pages_location', 'href', allow_duplicate=True),
    Input('redirect_child', 'id'),
    State('_pages_location', 'pathname'),
    prevent_initial_call=True
)
def redirect_child(i, p):
    for page in dash.page_registry.values():
        if page['path'] == p and page.get('top_nav'):
            for pg in dash.page_registry.values():
                if page['path'][1:] == pg.get('submenu') and pg.get('first_child'):
                    return pg['path']
    return dash.no_update

if __name__ == " __main__":
    app.run_server(debug=True)

```

topic\_2.py

```auto
from dash import html

import dash
import dash_bootstrap_components as dbc

from ..side_bar import sidebar

dash.register_page( __name__ , first_child=True, submenu='topics')

def layout():
    return dbc.Row(
        [dbc.Col(sidebar(), width=2), dbc.Col(html.Div("Topic 2 content"), width=10)]
    )

```

topic\_1

```auto
from dash import html

import dash

dash.register_page(
    __name__ ,
    name="Topics",
    top_nav=True,
    path='/topics'
)

def layout():
    return html.Div(id='redirect_child')

```

And I moved topic\_2 and topic\_3 into a folder “topics” to make the navigation line up with it.

* * *

You could probably make this a quicker interaction too by creating key-value dictionary with the mapping. 🙂

example:

```auto
import dash
from dash import Input, Output, State

import dash_bootstrap_components as dbc

app = dash.Dash(
    __name__ ,
    use_pages=True,
    external_stylesheets=[dbc.themes.BOOTSTRAP],
)

navbar = dbc.NavbarSimple(
    dbc.Nav(
        [
            dbc.NavLink(page["name"], href=page["path"])
            for page in dash.page_registry.values()
            if page.get("top_nav")
        ],
    ),
    brand="Multi Page App Demo",
    color="primary",
    dark=True,
    className="mb-2",
)

app.layout = dbc.Container(
    [navbar, dash.page_container],
    fluid=True,
)

routing_pairs = {}
for page in dash.page_registry.values():
    if page.get('top_nav'):
        for pg in dash.page_registry.values():
            if page['path'][1:] == pg.get('submenu') and pg.get('first_child'):
                routing_pairs[page['path']] = pg['path']

@app.callback(
    Output('_pages_location', 'href', allow_duplicate=True),
    Input('redirect_child', 'id'),
    State('_pages_location', 'pathname'),
    prevent_initial_call=True
)
def redirect_child(i, p):
    return routing_pairs.get(p) or dash.no_update

if __name__ == " __main__":
    app.run_server(debug=True)

```

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [September 19, 2023, 5:27pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/16 "2023-09-19T17:27:37Z")

</div>

Are you saying that the page for the top menu has no content other than the sub menus? If so, using #7 as an example, you would delete `topic_1.py` Then `topic2.py` is used in the top nav bar and just uses the name “Topics” for the nav link

---

<div class="post-metadata">

**Author:** ![etonblue](https://avatars.discourse-cdn.com/v4/letter/e/bb73d2/32.png) [@etonblue](https://community.plotly.com/u/etonblue)\
**Post date:** [September 19, 2023, 5:53pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/17 "2023-09-19T17:53:32Z")

</div>

Good gravy that is complicated. Couldn’t we just add a ‘parent’ tag to Pages or something? 🙃

Thank you @jinnyzor. It took me a while, but I finally got it to work. A couple of notes because it took me a while to adapt it to my situation:

1. I could not get the key-value dictionary version to work at all. Not sure why.
2. The ‘submenu’ variable must be the same name as the parent tab.
3. first-child=True should only be set on the sub page that you want to be default.
4. you can still use the ‘order’ keyword to determine the order of the subtabs.
5. the redirect\_child callback and function goes in the parent page (which in my case is not my app.py).

@AnnMarieW - I just saw your reply as I was posting this. How do you give a page both a “parent name” (e.g., Trucks) and a subtab name (e.g., Dump Trucks)? I can figure out how to get this:  
[Cars] [**Trucks**] [Planes]  
[**Trucks**][Dump Trucks]  
[**Trucks Page**]

but I can’t figure out how to get this:  
[Cars] [**Trucks**] [Planes]  
[**Garbage Trucks**][Dump Trucks]  
[**Garbage Trucks Page**]

where Trucks and Garbage Trucks refer to the same page.

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [September 19, 2023, 6:16pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/18 "2023-09-19T18:16:45Z")

</div>

Note that it’s not necessary to loop through the dash.page\_registry to create links - it’s just that it can be super convenient in huge projects with a lot of links and pages. To simplify things, you can start by doing things more “manually” then if you like, you can refactor to add more content to the dash.page\_registry if that makes it easier.

Try running example 7 locally. Delete topic\_1.py, then change the navbar in app,py to:

```auto

navbar = dbc.NavbarSimple(
    dbc.Nav(
        [
            dbc.NavLink("Home", href="/"),
            dbc.NavLink("About", href="/about"),
            dbc.NavLink("Topics", href="/topic-2"),
        ],
    ),
    brand="Multi Page App Demo",
    color="primary",
    dark=True,
    className="mb-2",
)

```

---

<div class="post-metadata">

**Author:** ![etonblue](https://avatars.discourse-cdn.com/v4/letter/e/bb73d2/32.png) [@etonblue](https://community.plotly.com/u/etonblue)\
**Post date:** [September 19, 2023, 8:42pm UTC](https://community.plotly.com/t/dash-pages-multi-page-app-with-subtabs-using-dbc-navlinks/72312/19 "2023-09-19T20:42:20Z")

</div>

Man this is fun! So I have now gotten it to work both ways! Thanks to both of you. I went with the easiest solution. It turns out that all I really needed to do was to add the “title” keyword, and then use page[‘title’] to control the display of the parent (‘Truck’) tab. I knew it would be easy!

Process:

1. delete the “Truck” page;

2. change the first (default) sub-tab’s registration to:

I used order to ensure that Garbage Truck would appear first. The second sub-tab’s registration became:

```
dash.register_page( __name__ , title = "Dump Truck", order=5)

```

1. the subnav function to (simply changed page[‘name’] to page[‘title’] for the display name):

This gives:

[Car][**Truck**][Plane]  
[**Garbage Truck**][Dump Truck]  
[**Garbage Truck Content**]

when truck is initially selected.

I knew it would be easy! Unless I’m missing something.

Thank you both for working through this!

**Edit:** Turns out I can only mark one solution, so I’m going to give it to @jinnyzor because of how fun his solution was.
