Can app.layout be Defined as a Function and Accept Keyword Arguments?

I am currently working on a multi-page application and have a question regarding the structure and definition of app.layout.

I understand that in a multi-page app, individual page layouts are defined in separate files and can be returned as functions. My question is about the main app.layout in app.py.

Is it possible to define app.layout as a function, and if so, can this function accept keyword arguments (**kwargs)? I have common components (dropdowns) in my app.layout that are same for all the pages. I would like to pass some kwargs to those components. Is this possible to achieve somehow?

Alternative is passing the same components into layout of each page but this is slower, harder to maintain, less readable etc.

Hi @davzup89

I don’t think that’s supported in dash. However, you can update the common components in the app.layout with a callback.

I noticed however that callbacks with _pages_location would only work in case if **kwargs are passed to layout.

@callback(
   
    Output("dropdown", "value"),
    Input('_pages_location', 'search'),
    prevent_initial_call=False
)

Hi @davzup89

Pages has a built-in utility that converts the dcc.Location search prop to a nice Python dict and pass it to a page layout function.

To use the search prop to update a component in app.layout you need to write your own utility.

When you run this example it, try adding a search to the url, and you will see the dropdown updates to show A

http://127.0.0.1:8050/?value=A
import dash
import dash_bootstrap_components as dbc
from dash import dcc, Input, Output, callback
from urllib.parse import parse_qs

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

def parse_query_string(search):
    """
    parse url query string
    example: converts "?city=NY&country=USA" to {"city":"NY", "country":"USA"}

    """
    if search and len(search) > 0 and search[0] == "?":
        search = search[1:]
    else:
        return {}

    parsed_qs = {}
    for (k, v) in parse_qs(search).items():
        v = v[0] if len(v) == 1 else v
        parsed_qs[k] = v
    return parsed_qs



navbar = dbc.NavbarSimple(
    dbc.DropdownMenu(
        [
            dbc.DropdownMenuItem(page["name"], href=page["path"])
            for page in dash.page_registry.values()
            if page["module"] != "pages.not_found_404"
        ],
        nav=True,
        label="More Pages",
    ),
    brand="Multi Page App Demo",
    color="primary",
    dark=True,
    className="mb-2",
)

dropdown = dcc.Dropdown(["A", "B", "C"], id="common-dropdown")

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

@callback(
    Output("common-dropdown", "value"),
    Input('_pages_location', 'search'),
)
def update(seach):
    parsed =  parse_query_string(seach)
    return parsed.get("value")

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


1 Like

Great! Thank you!