st.rerun() reset st.toggle() state

This work intended, as clicking the button does not reset the toggle.

st.toggle(
    "toggle",
    value=st.session_state.get("config_toggle", False),
    key="config_toggle",
)
if st.button("Rerun"):
  st.rerun()

But if put the button to the top

if st.button("Rerun"):
  st.rerun()
st.toggle(
    "toggle",
    value=st.session_state.get("config_toggle", False),
    key="config_toggle",
)

Then clicking the button resets the toggle.

  1. Are you running your app locally or is it deployed?
    locallly
  2. Share the Streamlit and Python versions.
    Streamlit, version 1.45.0. python 3.12.7

That is expected, because there is a rerun in which the toggle is not shown and its state is lost.

Is there a way to work around this?
Even the widget is not shown, but its state in session_state should be kept?

Many ways, for your contrived example, but they may or may not work for your actual case.

The most obvious way would be not calling st.rerun(). It doesn’t do anything useful in your example.

If you really, really need to call st.rerun() (do you?), then I would say, use session_state instead of the value parameter to set the initial value of the toggle. Except it doesn’t work for some reason. Probably related to a longstanding bug.

# This code should fix the issue, but it actually doesn't.
st.session_state.setdefault("config_toggle", False)
if st.button("Rerun"):
    st.rerun()
st.toggle("toggle", key="config_toggle")

Another option is calling st.button() after calling st.toggle, but using a container to make the button appear above the toggle. This does work.

st.session_state.setdefault("config_toggle", False)
container = st.container()
st.toggle("toggle", key="config_toggle")
if container.button("Rerun"):
    st.rerun()

Or just store the value of the button and call st.rerun() at the end if appropriate.

st.session_state.setdefault("config_toggle", False)
must_rerun = st.button("Rerun")
st.toggle("toggle", key="config_toggle")
if must_rerun:
    st.rerun()