A few years back we built an internal corporate site using Flask AppBuilder (FAB) and hosting various Dash dashboards in it using iframe. We’re now refreshing the site and decided to try remove FAB and try go all-in on Dash Pages and dash-auth with OIDC, mostly due to iframe ugliness and waning FAB support. Our hope was to keep code changes to a minimum within the pages and dashboards themselves even if the ‘wrapper’ changed a lot.
We easily switched our jinja2 pages to be Dash Pages using dcc.Markdown to show the rendered templates, but ironically we’ve hit a wall with converting the hosted Dash pages. I had assumed that each Page would work like our hosted Dash instances, with each layout being dynamically loaded when the Page was changed, but it appears Dash actually builds all Page layouts at initial load and just switches which one is displayed.
This causes us issues as we duplicate a lot of standard elements across the dashboards using shared utility methods, such as office-dropdown or org-unit-table. With all the layouts now in one Dash instance, the duplication of ID’s causes callback errors for duplicate Output targets that must be renamed, or when used as Input or State don’t raise errors but cause inconsistent or broken behaviour. It appears I need to rename every element on every layout to have a fully unique ID, which then cascades to renaming the callback method parameters, etc etc. It’s rather more change than I would like, especially as it will cause a lot of ugly or duplicated code where we used to just have simple shared methods. I can’t see a way around though, unless I am missing something?
The other option would be to keep using a Flask wrapper to control routing to each individual Dash, but with all the page layout including ‘chrome’ being rendered by each individual Dash. However, I’m only aware of the Enterprise Middleware for doing this without iframe, unless there’s another way?
It’s also possible to reuse components with the same ID across pages. This is useful if you want to sync their values across pages. Here’s an example app that demonstrates this.
You can also reuse layout components like a navbar across multiple pages — see this example where a shared component is imported and used in several layouts.
If you decide Dash Pages isn’t the right fit and would prefer to keep separate apps per route, the simplest option is Dash Enterprise. But if that’s not an option for you, then you could try using Werkzeug’s DispatcherMiddleware to mount multiple Dash apps under different paths.
Thanks @AnnMarieW, that’s very useful. I’ll have a look later in the week to see if any of those works for us, as I really like the simplicity of Pages. We’re small-ish charity with zero budget, so Enterprise is not an option!
One concern is how well does Pages scale? We have about 15 dashboards already with more planned, I’m concerned at the initial start-up time for loading all the layouts in a single Dash.
Syncing values across pages may come in handy for some of our dashboards, but one concern I have is if say I reuse the office-dropdown ID across multiple pages, won’t changing the office on one page then trigger callbacks on all the pages? That could be computationally expensive. Or do only the current page callbacks trigger?
As far as scaling goes - Dash multi-page apps scale well. A good example is the Dash documentation site, which is a large multi-page Dash app. It doesn’t use the newer Pages feature since it was built before that existed, but it shows that Dash can handle large apps with many pages without issues.
The Pages feature doesn’t change how Dash performs — it just makes it easier to build and organize multi-page apps by handling routing and layout registration for you.