Allowing for Multiple App Layouts

Good day, All,

I was approaching an issue recently at work. I wanted to give the ability for my clients to view information directly from the system, without also loading the rest of the dash layout for pages.

This is the default behaviour of Dash:

image

Notice, the navbar is repeated onto the secondly opened window. This can lead to issues with the client not knowing which browser they were working in prior, as well as when all you want to give is info and possibly a button to go back to the main website, this is a lot.

Or say, you want to create a document print out, it’d be easier to not display the navigation that the dash app automatically provides.

The end result is something like this:

When opened into a new window/tab, the default dash Layout is not applied.

Now, you could use some callbacks to make the navigation hidden, but that also requires loading of resources that arent necessary in the new window. Which, if you have a heavier dash layout, this can be a beast.

You could also use some flask routes directly in order to skirt this issue, but Flask cant always emulate your styling within the dash app.


With all that said, this is what I came up with.

Since Dash is built upon Flask, we have the ability to look at the headers inside the flask request, this grants access to know where the Dash Layout request came from Referer. From this, we can then determine if we want to cater a different Dash Layout.

Here is the resulting test code, try it out:

import dash_bootstrap_components as dbc
import dash
from dash import Dash, html, dcc
import flask

navbar = dbc.NavbarSimple(
    children=[
        dbc.NavItem(dbc.NavLink("Home", href="/")),
        dbc.NavItem(dbc.NavLink("Test 1", href="/test1", target='_blank', external_link=True)),
        dbc.NavItem(dbc.NavLink("Test 2 - not new", href="/test2")),
        dbc.NavItem(dbc.NavLink("Test 2", href="/test2", target='_blank', external_link=True))
    ],
    brand="NavbarSimple",
    brand_href="#",
    color="primary",
    dark=True,
)

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

def layout():
    if not flask.request:
        return html.Div()
    if flask.request.headers.get('Referer'):
        if 'test2' in flask.request.headers['Referer']:
            return layout2()
    return layout1()

def layout1():
    return html.Div([navbar, dash.page_container])

def layout2():
    return html.Div([dash.page_container])

dash.register_page('Test 1', path='/test1', layout=html.Div('this is a test with a regular layout'))
dash.register_page('Test 2', path='/test2', layout=html.Div('this is a test with a 2nd layout, when loaded independently notice no navbar'))
dash.register_page('Home', path='/', layout=html.Div('this is an example of how to do multiple layouts within the same Dash app'))

app.layout = layout

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

There are some caveats, this obviously requires using flask as the server and the layout has to be a function. :slight_smile:

I know that this might not be beneficial to many people, but I think this is a nice way to bring cohesion to the app and flexibility to what Dash can do.


I understand that for regular popups, you can use modals, and that is a way that I recommend unless this is needed

The benefit of using something like this, you now have a url that will take you directly to the info without all the other expensive requests from the server.

3 Likes

Thanks @jinnyzor, I always appreciate these kind of tips&tricks a lot.

It’s really interesting to see the vast amount of possibilities we have to create functionality or behavior of apps.

I surely will remember this topic when I need something similar.

:raised_hands:

1 Like