Hey, thanks for your thoughtful question and for sharing your code!
You’re right: simply setting st.session_state.disabled = False at the end of your process won’t immediately re-enable widgets, because Streamlit only updates widget states on rerun. Using st.rerun() after your process does reset the UI, but it also clears transient outputs like st.toast() since the script restarts from the top and doesn’t “remember” the toast.
The recommended approach is to save any outputs you want to persist (like a “done” message) in st.session_state, then display them after rerun. For example, set a flag like st.session_state.show_done = True before calling st.rerun(), and then conditionally show the toast at the top of your script if that flag is set. This way, the UI updates and your message persists for at least one rerun cycle. See the code below for a pattern that works well:
import streamlit as st
import time
if "disabled" not in st.session_state:
st.session_state.disabled = False
if "run_requested" not in st.session_state:
st.session_state.run_requested = False
if "show_done" not in st.session_state:
st.session_state.show_done = False
def start_run():
st.session_state.disabled = True
st.session_state.run_requested = True
st.button(
"Run process",
disabled=st.session_state.disabled,
on_click=start_run
)
if st.session_state.run_requested:
# Simulate long process
time.sleep(10)
st.session_state.run_requested = False
st.session_state.disabled = False
st.session_state.show_done = True
st.rerun()
if st.session_state.show_done:
st.toast("done")
st.session_state.show_done = False
This pattern ensures widgets are disabled during processing, re-enabled after, and your “done” message appears after rerun. For more details and variations, see this forum thread and this related discussion. If you run into issues, please share a minimum reproducible example and let the community jump in!
Sources: