Dark/light theme selection

On the latest version of streamlit if i do

def get_theme_state():
    # Initialize theme state if it doesn't exist
    if "theme_state" not in st.session_state:
        st.session_state.theme_state = {
            "current_theme": "light",
            "refreshed": True,
            
            "light": {
                "theme.base": "light",
                "theme.backgroundColor": "white",
                "theme.primaryColor": "#FFD700",
                "theme.secondaryBackgroundColor": "#f0f2f6",
                "theme.textColor": "#000000",
                "display_name": "Light Mode 🌞",
                "next_theme": "dark"
            },
            
            "dark": {
                "theme.base": "dark",
                "theme.backgroundColor": "#0e1117",
                "theme.primaryColor": "#FFD700",
                "theme.secondaryBackgroundColor": "#262730",
                "theme.textColor": "#ffffff",
                "display_name": "Dark Mode 🌙",
                "next_theme": "light"
            }
        }
    return st.session_state.theme_state

def change_theme():
    ts = get_theme_state()
    current = ts["current_theme"]
    next_theme = ts[current]["next_theme"]
    
    # Apply the theme settings
    for key, value in ts[next_theme].items():
        if key.startswith("theme."):
            st.set_option(key, value)
    
    # Update state
    ts["current_theme"] = next_theme
    ts["refreshed"] = False

def render_theme_selector():
    ts = get_theme_state()
    current_theme = ts["current_theme"]
    
    # Create the theme selector
    st.sidebar.selectbox(
        "Select Theme:",
        options=[ts["light"]["display_name"], ts["dark"]["display_name"]],
        index=0 if current_theme == "light" else 1,
        key="theme_selector",
        on_change=change_theme
    )
    
    # Handle refresh if theme was changed
    if not ts["refreshed"]:
        ts["refreshed"] = True
        st.rerun()

i get
StreamlitAPIException : theme.base cannot be set on the fly. Set as command line option, e.g. streamlit run script.py --theme.base, or in config.toml instead. Why cant we have the option of having a button for setting the theme ?

1 Like

st.set_option only works for a limited set of configuration options. Most configuration options have to be in place at startup. However, advanced theming is a popular request and on our current roadmap.

I recommend looking through GitHub issues to upvote the ones that interest you. For example: Allow multiple, named custom themes · Issue #6813 · streamlit/streamlit · GitHub

Not quite sure if this still works but you can try to use “st._config.set_option()”.
I used this with st.navigation to have a button that switches the mode.

However, I noticed that it will switch the mode for all users which is why I deleted it later on.

light = {"theme.base": "light"}
dark = {"theme.base": "dark"}


def change_mode(mode: dict):
    for k, v in mode.items():
        st._config.set_option(k, v)
    st.rerun()


def light_mode():
    st.session_state["other_mode"] = "Darkmode"
    change_mode(light)

def dark_mode():
    st.session_state["other_mode"] = "Lightmode"
    change_mode(dark)


if st._config.get_option("theme.base") == "dark":
    mode_page = st.Page(
        light_mode,
        title="Lightmode",
        icon=":material/light_mode:",
    )
else:
    mode_page = st.Page(dark_mode, title="Darkmode", icon=":material/dark_mode:")

page_dict["Settings"] = [mode_page]

pg = st.navigation(
    page_dict,
    position="sidebar",
)

pg.run()

StreamlitAPIException : theme.backgroundColor cannot be set on the fly. Set as command line option, e.g. streamlit run script.py --theme.backgroundColor, or in config.toml instead.

I get this error.

So far i left this in the water for the moment until this will be implemented.