Dash Bootstrap Templates V1.0.0 New: Theme Switch Components

Dash Bootstrap Templates V1.0.1

I’m please to announce the latest release of the dash-bootstrap-templates library :confetti_ball:

pip install dash-bootstrap-templates -U

See it live at Theme-Explorer

The dash-bootstrap-templates library provides:

  • Bootstrap themed Plotly figure templates. You will find a Plotly template for each of the 26 Bootstrap/Bootswatch themes available in the Dash Bootstrap Components Library. These templates will automatically style your figures with Bootstrap theme colors and fonts.

    • :new: 4 themes added: “morph”, “quartz”, “vapor” “zephyr”
  • Two All-in-One components to change themes in a Dash app.

    • :new: ThemeSwitchAIO toggles between two themes.

    • :new: ThemeChangerAIO select from multiple themes.

  • :new: The dbc.css stylesheet which styles Dash Core Components and the Dash DataTable with a Bootstrap theme. (This is really cool - more examples coming soon)

Note: The ThemeSwitchAIO and ThemeChangerAIO components and the dbc.css stylesheet requires dash-bootstrap-components>=1.0.0. It will only work with the themes included in `dash-bootstrap-components>=1.0.0

Figure Template Quickstart


from dash import Dash, dcc, html
import plotly.express as px
import dash_bootstrap_components as dbc

from dash_bootstrap_templates import load_figure_template

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
load_figure_template("bootstrap")


df = px.data.gapminder().query("continent != 'Asia'")  # remove Asia for visibility
fig = px.line(df, x="year", y="lifeExp", color="continent", line_group="country")


app.layout = dbc.Container(
    [
        html.H1("Dash Bootstrap Template Demo", className="bg-primary text-white p-2"),
        dbc.Row(dbc.Col(dcc.Graph(figure=fig))),
    ],
    fluid=True,
)


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

image

Demo App 2 - 4 Graphs Updated

This demo (code here), shows how the theme is applied to all 4 graphs.

figure_template2

Theme Switch Components

dash-bootstrap-templates has two All-in-One components to change themes.

  • The ThemeSwitchAIO is a switch with icons on the left and right, which is ideal for toggling between a light and a dark theme.

  • The ThemeChangerAIO has a button that opens an dbc.Offcanvas component which by default shows all the available themes.

Note the All-in-One component switches the Bootstrap stylesheet for the app and sets the default Plotly figure template for the theme, however, figures must be updated in a callback in order to render the figure with the new template. See the callback below for an example. The template_from_url is a helper function that returns the template name based on the theme url. For example template_from_url(dbc.themes.SLATE) returns "slate"

ThemeChangerAIO Quickstart


from dash import Dash, dcc, html, Input, Output
import pandas as pd
import plotly.express as px
import dash_bootstrap_components as dbc
from dash_bootstrap_templates import ThemeChangerAIO, template_from_url


dbc_css = (
    "https://cdn.jsdelivr.net/gh/AnnMarieW/dash-bootstrap-templates@V1.0.1/dbc.min.css"
)
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP, dbc_css])


df = pd.DataFrame(
    {
        "Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
        "Amount": [4, 1, 2, 2, 4, 5],
        "City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"],
    }
)
header = html.H4(
    "ThemeChangerAIO Demo", className="bg-primary text-white p-4 mb-2 text-center"
)
buttons = html.Div(
    [
        dbc.Button("Primary", color="primary"),
        dbc.Button("Secondary", color="secondary"),
        dbc.Button("Success", color="success"),
        dbc.Button("Warning", color="warning"),
        dbc.Button("Danger", color="danger"),
        dbc.Button("Info", color="info"),
        dbc.Button("Light", color="light"),
        dbc.Button("Dark", color="dark"),
        dbc.Button("Link", color="link"),
    ],
    className="m-4",
)
graph = html.Div(dcc.Graph(id="graph"), className="m-4")

app.layout = dbc.Container(
    [
        header,
        dbc.Row(
            [
                dbc.Col(ThemeChangerAIO(aio_id="theme", radio_props={"value":dbc.themes.FLATLY}), width=2,),
                dbc.Col([buttons, graph],width=10),
            ]
        ),
    ],
    className="m-4 dbc",
    fluid=True,
)


@app.callback(
    Output("graph", "figure"), Input(ThemeChangerAIO.ids.radio("theme"), "value"),
)
def update_graph_theme(theme):
    return px.bar(
        df, x="Fruit", y="Amount", color="City", barmode="group", template=template_from_url(theme)
    )


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

theme_changer



Here is the same app, but using a the ThemeSwitchAIO component to toggle between two themes.
See the (code here).

It’s also possible to change the icons. See an example of using Bootstrap icons instead of the default FontAwesome icons here.

theme_toggle

Background

Dash Labs is Plotly library that explores new features for future releases of Dash. In Dash Labs V0.4.0, there was a cool feature where Bootstrap themed figure templates were created “on the fly”. This was a part of the layout templates project that is no longer being developed.

Even though these Bootstrap themed figure templates will not be included in Dash, the dash-bootstrap-templates makes them available to you. The figure templates are created using the Dash Labs’ algorithms and saved in json format. When you use load_figure_template() in your app, it loads the json file, adds it to plotly.io and sets it as the default figure template for an app. See more information about Plotly figure templates here.

Available Themes

This library provides a figure template for the following Bootstrap/Bootswatch themes:

valid_themes = [
“bootstrap”,
“cerulean”,
“cosmo”,
“flatly”,
“journal”,
“litera”,
“lumen”,
“lux”,
“materia”,
“minty”,
“pulse”,
“sandstone”,
“simplex”,
“sketchy”,
“spacelab”,
“united”,
“yeti”,
“cyborg”,
“darkly”,
“slate”,
“solar”,
“superhero”,
“morph”,
“quartz”,
“vapor”
“zephyr”
]

ThemeChangerAIO Reference

ThemeChangerAIO is an All-in-One component composed of a parent html.Div with
the following components as children:

  • dbc.Button ("switch") Opens the Offcanvas component for user to select a theme.
  • dbc.Offcanvas ("offcanvas")
  • dbc.RadioItems ("radio"). The themes are displayed as RadioItems inside the dbc.Offcanvas component.
    The value is a url for the theme
  • html.Div is used as the Output of the clientside callbacks.

The ThemeChangerAIO component updates the stylesheet when the value of radio changes. (ie the user selects a new theme)

  • param: radio_props A dictionary of properties passed into the dbc.RadioItems component. The default value is dbc.themes.BOOTSTRAP
  • param: button_props A dictionary of properties passed into the dbc.Button component.
  • param: offcanvas_props. A dictionary of properties passed into the dbc.Offcanvas component
  • param: aio_id The All-in-One component ID used to generate components’ dictionary IDs.

The All-in-One component dictionary IDs are available as:

  • ThemeChangerAIO.ids.radio(aio_id)
  • ThemeChangerAIO.ids.offcanvas(aio_id)
  • ThemeChangerAIO.ids.button(aio_id)

ThemeSwitchAIO Reference

ThemeSwitchAIO is an All-in-One component composed of a parent html.Div with the following components as children:

  • dbc.Switch ("switch") with icons to the left and right of the switch.
  • dcc.Store ("store") The themes are stored in the data prop.
  • html.Div is used as the Output of the clientside callbacks.

The ThemeSwitchAIO component updates the stylesheet when triggered by changes to the value of switch or when
the themes are updated in the “store” component. The themes in the switch may be updated in a callback
by changing the theme urls in the “store” component.

  • param: themes A list of two urls for the external stylesheets. The default is [dbc.themes.CYBORG, dbc.themes.BOOTSTRAP].
  • param: icons A dict of the icons to the left and right of the switch. The default is
    {"left" :"fa fa-moon", "right" :"fa fa-sun"}.
  • param: aio_id The All-in-One component ID used to generate component’s dictionary IDs.

The All-in-One component dictionary IDs are available as

  • ThemeSwitchAIO.ids.switch(aio_id)
  • ThemeSwitchAIO.ids.store(aio_id)

Contributors

Special thanks to @tcbegley and @emilhe for their help with this project. Thanks also to @congnd91 for help with the dbc.css.

4 Likes

Awesome work @AnnMarieW!

1 Like

@AnnMarieW This is great! Makes it super easy for the user to change themes!

1 Like

Great work, very helpful.
However I encountered “Cannot set properties of undefined (setting ‘href’)”
on the browser during applying to my app with “debug=True” mode
It can work properly after that error , but I want to fix it.
I am now investigating this error but do you have any advice?

Hi @takashi
Thanks for using dash-bootstrap-templates! The current version is now 1.0.4. (I’ll update the instructions)
If you still get that error after upgrading:

pip install dash-bootstrap-templates  -U

Could you please tell me when you you get the error - Is it with one of the theme switch components?

Also, could you check your version of dash-bootstrap-components? It requires verion 1.0.0 or greater

Hello Ann

I found my mistake.
my script defined external_stylesheets=[[url_theme1, dbc_css], dbc.icons.FONT_AWESOME],
just copy and paste the demo script.and add font awesome
I deleted inner bracket, it worked correctly FANTASCTIC.
Thank you for your kind help.

1 Like

Hello,
Is it possible to chose only from several themes in ThemeChangerAIO and not to have all of them?
Thank you!

Hi @stefan_1803

That’s a great question - I had to read my docs :slight_smile:

Yes, the AIO Theme switch component uses a dbc.RadioItems to display the themes in the offcanvas component. You can use the radio_props to update the options. Here is a complete example where only three themes are displayed:


from dash import Dash, dcc, html, Input, Output
import pandas as pd
import plotly.express as px
import dash_bootstrap_components as dbc
from dash_bootstrap_templates import ThemeChangerAIO, template_from_url


dbc_css = (
    "https://cdn.jsdelivr.net/gh/AnnMarieW/dash-bootstrap-templates@V1.0.1/dbc.min.css"
)
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP, dbc_css])


df = pd.DataFrame(
    {
        "Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
        "Amount": [4, 1, 2, 2, 4, 5],
        "City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"],
    }
)
header = html.H4(
    "ThemeChangerAIO Demo", className="bg-primary text-white p-4 mb-2 text-center"
)
buttons = html.Div(
    [
        dbc.Button("Primary", color="primary"),
        dbc.Button("Secondary", color="secondary"),
        dbc.Button("Success", color="success"),
        dbc.Button("Warning", color="warning"),
        dbc.Button("Danger", color="danger"),
        dbc.Button("Info", color="info"),
        dbc.Button("Light", color="light"),
        dbc.Button("Dark", color="dark"),
        dbc.Button("Link", color="link"),
    ],
    className="m-4",
)
graph = html.Div(dcc.Graph(id="graph"), className="m-4")

themes_options = [
    {"label": "Flatly", "value": dbc.themes.FLATLY},
    {"label": "Darkly", "value": dbc.themes.DARKLY},
    {"label": "Minty", "value": dbc.themes.MINTY},
]


app.layout = dbc.Container(
    [
        header,
        dbc.Row(
            [
                dbc.Col(
                    ThemeChangerAIO(
                        aio_id="theme",
                        radio_props={
                            "value": dbc.themes.FLATLY,
                            "options": themes_options,
                        },
                    ),
                    width=2,
                ),
                dbc.Col([buttons, graph], width=10),
            ]
        ),
    ],
    className="m-4 dbc",
    fluid=True,
)


@app.callback(
    Output("graph", "figure"),
    Input(ThemeChangerAIO.ids.radio("theme"), "value"),
)
def update_graph_theme(theme):
    return px.bar(
        df,
        x="Fruit",
        y="Amount",
        color="City",
        barmode="group",
        template=template_from_url(theme),
    )


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


1 Like

Awesome, thank you very much! May I kindly ask couple of questions more?

  1. dash_table.DataTable, dcc.Dropdown, html.Button are not affected by the theme change, is there a way to do it?
  2. Is there a way to have a custom theme by default and bootstrap ones as an options, or if you’re going to use them, you must have one loaded?
  3. Can a user save theme choice to be his/hers default?
  4. Is it possible to affect all pages of the app with the theme change?

Thank you very much in advance!

Hi @stefan_1803

In response to your questions:

  1. I’d recommend using dbc.Button rather than html.Button so the theme gets updated automatically. For other dcc components, this post on styling the DataTable with a Bootstrap Theme might be helpful, and also see my site for more information:
  1. This theme switch component only handles Bootstrap 5 Themes. However, it would be possible to use a customized Bootstrap 5 theme.

  2. For a user default, you might try adding the persistance prop to the RadioItems.

  3. Yes, it’s possible to have the theme change affect all pages. You would just need to include the theme switch component in app.py . See an example GitHub - AnnMarieW/dash-multi-page-app-demos: Minimal examples of multi-page apps using the pages feature in dash>=2.5.1

Hi Ann Marie,
Thank you very much for your time and responses, keep up with the great work ! :slight_smile:

2 Likes