Update : version 2.6.0 has been released since this was posted.
Hey Dash enthusiasts,
Weāre excited to announce that Dash 2.5.0 & 2.5.1 have been released. 2.5.1 contains a small bug fix for one of the features in 2.5.0. These are a backwards compatible releases and we recommend going straight to 2.5.1
.
pip install dash==2.5.1
Official Changelog Dash v2.5.0 and v2.5.1
Highlights
Improved Multipage Experience with Pages
Dash Pages
implements features to simplify creating a multi-page app, handling URL routing and offering an easy way to structure and define the pages in your app.
There are many advantages of using Pages
to build a multi-page app - it will automatically:
- import the pages from the pages folder
- handle nested folders within the pages folder
- handle the routing
- update the title in the browser for each page
- create meta tags for sharing links on social media that include title, description and image
- pass variables from the url query strings to the page layout function
- pass variables from the url pathname to the layout function
- create a default 404 not found page, with the ability to provide a custom 404 page
- redirect to other pages, when redirect paths are specified.
- Set
validate_layout
under-the-hood to avoid callback exceptions
Tutorial - create multipage app with Pages
Check out this beautiful multipage App created by our very own community member, @raptorbrad.
There are three basic steps for creating a multi-page app with Dash Pages:
- Create individual
.py
files for each page in your app, and put them in a/pages
directory. - In each of these page files:
- Add a
dash.register_page(__name__)
, which tells Dash that this is a page in your app. - Define the pageās content within a variable or function called
layout
.
- Add a
- In your main app file,
app.py
:- When declaring your app, set
use_pages
toTrue
:app = Dash(__name__, use_pages=True)
- Add
dash.page_container
in your appās layout where you want the content of the pages to be displayed for when the user visits one of the appās page paths.
- When declaring your app, set
Letās see an example of a multipage app with 3 pages and 1 app.py file, which is the entry point to our 3 pages.
Folder structure:
- app.py
- assets
- pages
|-- analytics.py
|-- home.py
|-- archive.py
The Code:
`pages/analytics.py` :
import dash
from dash import html, dcc, callback, Input, Output
dash.register_page(__name__)
layout = html.Div([
html.H1('This is our Analytics page'),
html.Div([
"Select a city: ",
dcc.RadioItems(['New York City', 'Montreal','San Francisco'],
'Montreal',
id='analytics-input')
]),
html.Br(),
html.Div(id='analytics-output'),
])
@callback(
Output('analytics-output', 'children'),
Input('analytics-input', 'value')
)
def update_city_selected(input_value):
return f'You selected: {input_value}'
`pages/home.py` :
import dash
from dash import html, dcc
dash.register_page(__name__, path='/')
layout = html.Div(children=[
html.H1('This is our Home page'),
html.Div('This is our Home page content.'),
])
`pages/archive.py` :
import dash
from dash import html, dcc
dash.register_page(__name__)
layout = html.Div([
html.H1('This is our Archive page'),
html.Div('This is our Archive page content.'),
])
And our main app file.
`app.py` :
from dash import Dash, html, dcc
import dash
app = Dash(__name__, use_pages=True)
app.layout = html.Div([
html.H1('Multi-page app with Dash Pages'),
html.Div(
[
html.Div(
dcc.Link(
f"{page['name']} - {page['path']}", href=page["path"]
)
)
for page in dash.page_registry.values()
]
),
dash.page_container # this is where each of the pages' content will be displayed.
])
if __name__ == '__main__':
app.run_server(debug=True)
Important: Use @dash.callback
instead of @app.callback
so that you donāt have circular imports. If you need access to the app object, use app = dash.get_app()
Pages has many more features like redirects, meta tags, nested pages, and more. Make sure to read the complete docs to learn more.
Additional multipage app examples with Pages. This GitHub repo is community-created & maintained.
Pages was developed in the open with collaboration from the Dash Community. Many thanks to everyone, and especially to @AnnMarieW for leading this effort! View the original discussion & announcement.
Sharing is Caring: If you have already made a multipage app with Pages, weād love to see it. Donāt forget to share it on the show-and-tell tag.
if you had built a multipage app with the dash-labs pages
plugin, follow these 3 steps to make your app compatible with Dash 2.5.1 or higher:
-
Remove
import dash_labs as dl
or upgrade dash-labs to V1.1.0. -
In the main app file, change:
app = Dash(__name__, plugins=[dl.plugins.pages])
to:
app = Dash(__name__, use_pages=True)
-
And change:
dl.plugins.page_container
to:
dash.page_container
Component Properties
Since the beginning of Dash, a fundamental limitation in our component architecture was that the only component property that could accept other components was the children
property.
In the React ecosystem, many components allow you to pass other components in as properties. In Dash 2.5, weāve updated the foundational architecture to enable component authors to accept components in arbitrary properties, not just children. This unlocks great potential for richer components, easier customization across the component ecosystem, and greater parity with 3rd party React components.
Any property that might accept a string could be a good candidate for accepting a component as well. Accepting components instead of strings allows end users to easily modify the style of the string with e.g. html.Span('my label', style={'color': 'hotpink'})
. Imagine the ability to pass in html.Img
in various labels or dcc.Graph
in table cells.
In Dash 2.5, weāve used this feature to expand the API for 3 components, dcc.Dropdown
, dcc.Checklist
, and dcc.RadioItems
. These components can take other Dash components for label
within the options
property.
If in the past the Dropdown options were written as such:
dcc.Dropdown(options=[
{'label':'Montreal', 'value':'Montreal'},
{'label':'New York City', 'value':'NYC'},
{'label':'San Francisco', 'value':'SF'}
])
Now you can assign components into the label
. One advantage of this is enhanced styling of dropdown options. For example, in the code below the html.Div
component is assigned to the label
of the Dropdown:
dcc.Dropdown(options=[
{'label':html.Div('Montreal', style={'color': 'Orange', 'font-size': 20}), 'value':'Montreal'},
{'label':html.Div('New York City', style={'color': 'Purple', 'font-size': 20}), 'value':'NYC'},
{'label':html.Div('San Francisco', style={'color': 'Blue', 'font-size': 20}), 'value':'SF'}
])
Another advantage of assigning Dash components to label
is that you can have more than just a string type variable as part of the options property. Hereās an example of an image combined with a string, assuming your image files are in the assets folder.
dcc.Dropdown(options=[
{
'label':html.Div([
html.Img(src="/assets/python_50px.png", height=30),
html.Div("Python", style={'font-size': 15, 'padding-left': 10}),
], style={'display': 'flex', 'align-items': 'center', 'justify-content': 'center'}),
'value':'Py'
},
{
'label':html.Div([
html.Img(src="/assets/r_50px.png", height=30),
html.Div("R", style={'font-size': 15, 'padding-left': 10}),
], style={'display': 'flex', 'align-items': 'center', 'justify-content': 'center'}),
'value':'R'
},
{
'label':html.Div([
html.Img(src="/assets/julia_50px.png", height=30),
html.Div("Julia", style={'font-size': 15, 'padding-left': 10}),
], style={'display': 'flex', 'align-items': 'center', 'justify-content': 'center'}),
'value':'Jul'
},
])
For more examples, see:
- Dropdown ā Components as Option Labels
- Checklist ā Components as Option Labels
- RadioItems ā Components as Option Labels
Component Properties fireside chat
Notable Bug Fixes & Minor Changes
- #2049 Added
wait_for_class_to_equal
andwait_for_contains_class
methods todash.testing
- #2087 - Fix bug #2086 in which using id as a key within a componentās id breaks the new callback contextās
args_grouping
function. - #2084 - In dash 2.5.0, a default viewport meta tag was added as recommended for mobile-responsive sites by mdn. This feature can be disabled by providing an empty viewport meta tag. e.g.
app = Dash(meta_tags=[{"name": "viewport"}])
- #2090, #2092. Fixed bug where the
path
to thepages_folder
was incorrect on Windows. - #2043 - Fix bug #2003 in which
dangerously_allow_html=True
+mathjax=True
works in some cases, and in some cases not. - #2065 - Fix bug #2064 rendering of
dcc.Dropdown
when a value is provided but no options. - #2047 - Fix bug #1979 in which
DASH_DEBUG
as environment variable gets ignored. Thank you @PGrawe for the contribution. - #2070 - Fix bug #2066 nested types triggering maximum call stack error when building typescript components.
- #2050 - Changed
find_element
andfind_elements
to accept anattribute
argument that aligns with SeleniumāsBy
class, allowing you to search elements by other attributes. Default value isCSS_SELECTOR
to maintain backwards compatibility with previousfind_elements
. Thank you to @MrTeale for this contribution
Previous Releases
Dash 2.4 Released - Improved Callback Context, Clientside Callback Promises, Typescript Components, Minor Ticks, and More!
Dash 2.3.0 Release - MathJax and fillpattern option in scatter trace
Dash 2.2.0 Release - Adds ticklabelstep
to axes, and added dash.get_asset_url
Dash 2.1.0 Release - Autogenerated IDs and reƤrranged keyword arguments in Dash components
Dash 2.0 Prerelease Candidate Available!