# Sharing components between pages

**URL:** <https://community.plotly.com/t/sharing-components-between-pages/78742>\
**Category:** Dash Python\
**Created:** [September 22, 2023, 5:23pm UTC](https://community.plotly.com/t/sharing-components-between-pages/78742 "2023-09-22T17:23:08Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Emil](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/emil/32/31734_2.png) [@Emil](https://community.plotly.com/u/Emil)\
**Post date:** [September 22, 2023, 5:23pm UTC](https://community.plotly.com/t/sharing-components-between-pages/78742/1 "2023-09-22T17:23:08Z")

</div>

I am working on an application where the routing between pages has been implemented by adding elements to the layout initially, and then changing their visibility based on the url. In principle, a structure like this,

```auto
from dash import Dash, html, dcc, Output, Input

app = Dash()
app.layout = html.Div([
    html.Div(["Page1", dcc.Link("Go to page2", href="/page2")], id="page1"),
    html.Div(["Page2", dcc.Link("Go to page1", href="/page1")], id="page2", hidden=True),
    dcc.Location(id="location") 
])

@app.callback(Output("page1", "hidden"),
              Output("page2", "hidden"),
              Input("location", "pathname"))
def navigate(pathname):
    if "page2" in pathname:
        return [True, False]
    return [False, True]

if __name__ == ' __main__':
    app.run_server(port=9999)

```

While this approach works, it quickly grows in complexity, and the application is already at a point where people are loosing the overview. I was thinking about migrating the app to use [Dash pages](https://dash.plotly.com/urls), as this seems like a much cleaner and more scaleable approach.

However, the initial approach has one main advantage from the user perspective: The **state is kept** when the user navigates between pages. Hence, selections in drop downs are remembered, tables remain populated and so on. I know that (some of) this behavior can be achieved using [persistence](https://dash.plotly.com/persistence), but that requires a lot more work/configuration. And I am not sure that it will be suitable for large amounts of data (e.g. a large aggrid).

To make matters more challenging, some component are also _shared_ between pages. It could be e.g. a large aggrid, that is used on multiple pages, and which takes a long time (several seconds) to populate. With the pages approach, I need to populate the grid on every page change - but with the toggle visbility approach, this can be avoided (at the cost of even more complex navigation code).

In essence, I don’t see any (easy) way of keeping the user experience intact, if we migrate to Dash pages. Has anyone faced similar challenges? How did you address them? 🙂

---

<div class="post-metadata">

**Author:** ![RenaudLN](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/renaudln/32/9041_2.png) [@RenaudLN](https://community.plotly.com/u/RenaudLN)\
**Post date:** [September 22, 2023, 8:28pm UTC](https://community.plotly.com/t/sharing-components-between-pages/78742/2 "2023-09-22T20:28:21Z")

</div>

I just started a Dash [PR](https://github.com/plotly/dash/pull/2647) to be able to add more data passed to the layout functions of the pages routing. This would allow to have a central app state Store that passes all config to pages layout functions.

This doesn’t answer your question of the large datable though. For this one I would probably have the data in a Store or hidden table in the main layout then something that syncs the data clientside when you use it in the different pages.

---

<div class="post-metadata">

**Author:** ![Emil](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/emil/32/31734_2.png) [@Emil](https://community.plotly.com/u/Emil)\
**Post date:** [September 24, 2023, 2:07pm UTC](https://community.plotly.com/t/sharing-components-between-pages/78742/3 "2023-09-24T14:07:03Z")

</div>

@RenaudLN that looks nice! However, as you note, it won’t solve this issue with the large datatable. I believe clientside sync with a `Store` will still be too slow, as it takes (significant) time just to render the datatable.

I have created a [small extension to dash pages](https://github.com/emilhe/dash-extensions/blob/dynamic_components/dash_extensions/pages.py) that enables _dynamic components_, i.e. components where the visibility depends on the URL. Similar to pages, you add the parent container to the app layout,

```python
from dash import html, page_container
from dash_extensions.pages import setup_dynamic_components
...

app.layout = html.Div([
    ...
    dash.page_container,
    setup_dynamic_components()
])

```

and pass the component(s) as part of the page registration,

```python
import dash
from components import my_data_table

dash.register_page( __name__ , components=[my_data_table])

```

to indicate which component(s) should be visible on this page. I have only done a bit of testing, but it seems to work as intended. You can try it if you want with by installing `dash-extensions==1.0.4rc1`. If there is interest, I guess this functionality could be turned into a PR to Dash pages 🙂

The main drawback of this solution is that you can’t mix dynamic components with the layout of your (Dash pages) page; you can only place them above or below. The only possible workaround I have found would be to use [CSS Grid](https://www.w3schools.com/cssref/pr_grid-area.php) for positioning; but as I understand, that would only work, if the dynamic components are located _inside_ the dash\_pages container (all the grid elements must have the same parent). And to do that, the pages update mechanism would need to be changed a partial update (to avoid reloading the dynamic components).

---

<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 24, 2023, 4:11pm UTC](https://community.plotly.com/t/sharing-components-between-pages/78742/4 "2023-09-24T16:11:51Z")

</div>

Hi @RenaudLN and @Emil

These are great new features for Pages!

@Emil if it doesn’t work to put the dynamic component (such as a large grid) above or below `dash.page_container` how about making the dynamic component the entire layout for the page?

```auto
dash.register_page( __name__ , components=[layout], layout=html.Div())

```

---

<div class="post-metadata">

**Author:** ![AlexM](https://avatars.discourse-cdn.com/v4/letter/a/3da27b/32.png) [@AlexM](https://community.plotly.com/u/AlexM)\
**Post date:** [October 4, 2023, 2:07pm UTC](https://community.plotly.com/t/sharing-components-between-pages/78742/5 "2023-10-04T14:07:13Z")

</div>

Hi @Emil,

a quick question about the components argument in `dash.register_page( __name__ , components=[my_data_table])`.

What gets passed to components?

I was thinking it would be callback output ID’s i.e. if the callback looked something like this:

```auto
@callback([Output('plotting_complete_message', 'children'),
           Output('plot_1', 'figure'),
           Output('plot_2', 'figure')],
          [Input('dataframe_1', 'data')])
  
def plot_generator_1(dataframe_1):
       # Check if input does not contain data and prevent app update.
       if dataframe_1 is None:
            raise PreventUpdate

       # Check if input contains data and trigger callback.
       elif dataframe_1 is not None:
            some code that returns plot_1 and plot_2
 
            plotting_complete_message = html.H3("Complete")

            return(plotting_complete_message, plot_1, plot_2)
       else:
            return(no_update, no_update, no_update)

```

Would the component(s) then be passed as follows:

**Page 1:**  
`dash.register_page( __name__ , components=['plotting_complete_message'])`

**Page 2:**  
`dash.register_page( __name__ , components=['plot_1', 'plot_2'])`

In this example the outputs of the callback are split between pages.

The wider back-ground here is that I’m migrating my 1 page multi-tab Dash dasboard to a Dash multi-page with mutli-tab web-app/dashboard. I’ve got an open question on this as I’m working on various challenges:

[https://community.plotly.com/t/a-nonexistent-object-was-used-in-an-output-of-a-dash-callback-correct-use-of-multi-page-app-validation/78864/6](https://community.plotly.com/t/a-nonexistent-object-was-used-in-an-output-of-a-dash-callback-correct-use-of-multi-page-app-validation/78864/6)

My web-app has a **Data Upload** page (Dash-uploader button used to drop zipped files) that contains a layout updated dynamically with “Complete” messages as various callbacks finish. These callbacks are as above, not only outputting the “Complete” message, but also the plots which are served to a **Visualisation** page. In my 1 page multi-tab approach, as “Complete” messsages appear for plots in upload tab, it’s then possible to see them in the visualisation tab. Clicking between tabs whilst this process is happening doesn’t refresh tab content and so it’s just to check progress.

In the multi-page app, I would like the same functionality. However, I get a refresh of page content as callbacks are re-initiated for plotting, when I click on the **Visualisation** page and vice versa. Still trying to understand, where in my callback chain this happens and how it relates to pages.

Thanks for your time.

Alex
