Sorry if I missed something as I'm fairly new to dash and on how callbacks work. So basically I'm working on a dashboard application using dash and python. My ultimate aim is to implement a dark mode option, which will be through the dash daq BooleanSwitch.
My Approach
The way I have implemented this is that I have two dictionaries that represent two color schemes: dark and light, with the exact same keys, but different values for color schemes. I currently am using the light dictionary to manually define the background color, font color, etc. into the styling options for each element inside my app layout. Here's what they look like:
light_theme = {
'main-background': '#ffe7a6',
'header-text': '#376e00',
'sub-text': '#0c5703'
}
dark_theme = {
'main-background': '#000000',
'header-text': '#ff7575',
'sub-text': '#ffd175'
}
I then call the light_theme dict into my main layout code here:
app.layout = html.Div(children=[
daq.BooleanSwitch(on=False, id='bool-switch-input'),
html.Div(id='bool-switch-output'),
html.H1(children="This is a heading text", id="head-txt", style={
'color': light_theme['header-text']
}),
html.H2(children="This is a subtext", id='sub-txt', style={
'color': light_theme['sub-text']
}),
], style={
'backgroundColor': light_theme['main-background']
})
Finally, I use the callback function to get the value from the switch on whether it is on or off:
@app.callback(Output('bool-switch-output', 'children'),
Input('bool-switch-input', 'on'))
def update_output(on):
return on
Now what I'm having trouble is making it so that whenever this switch is on (which is dark mode), all the html elements inside the layout use the dark_theme instead of light_theme dictionary. I was under the impression that by simply swapping the variables would be work but I'm not sure if that is possible from the callback function while the app is running. So, is there a better way to do this?
What I have already tried:
Making a custom javascript to set onclick property to switch and then accordingly changing the css layout. Unfortunately didn't work because according to the other forums, the js always gets fired first which results in a null value everytime.
Using clientside_callbacks, but I'm honestly lost on how to get that working.
If there is a different, better approach to this someone could recommend, I'd appreciate it.
import dash
from dash import Dash, dcc, html, Input, Output
from dash.exceptions import PreventUpdate
import dash_daq as daq
import plotly.express as px
import pandas as pd
from jupyter_dash import JupyterDash
app = JupyterDash(__name__)
light_theme = {
"main-background": "#ffe7a6",
"header-text": "#376e00",
"sub-text": "#0c5703",
}
dark_theme = {
"main-background": "#000000",
"header-text": "#ff7575",
"sub-text": "#ffd175",
}
app.layout = html.Div(
id="parent_div",
children=[
daq.BooleanSwitch(on=False, id="bool-switch-input"),
html.Div(id="bool-switch-output"),
html.H1(
children="This is a heading text",
id="head-txt",
style={"color": light_theme["header-text"]},
),
html.H2(
children="This is a subtext",
id="sub-txt",
style={"color": light_theme["sub-text"]},
),
],
style={"backgroundColor": light_theme["main-background"]},
)
@app.callback(
[
Output("parent_div", "style"),
Output("head-txt", "style"),
Output("sub-txt", "style"),
],
Input("bool-switch-input", "on"),
)
def update_output(on):
theme = dark_theme if on else light_theme
return (
{"backgroundColor": theme["main-background"]},
{"color": theme["header-text"]},
{"color": theme["sub-text"]},
)
if __name__ == "__main__":
app.run_server(mode="inline")