Hi there,
I would like to guide a user through a multi-step submission process and I am noticing some quirky interactions between st.form
and st.session_state
.
The two problems I am having are illustrated in the reprex below.
Problem 1
The st.session_state
key is lost if an associated widget disappears. This problem has been known for a while and a workaround is implemented below, but I am still curious if this can be fixed in some other way?
Problem 2
This is the main thing: with Streamlit’s re-run model, I would expect the following behaviour:
- First form input is isolated from the re-runs; the user can explore various options.
- Once the first st.form_submit_button is clicked,
st.session_state["step"]
is set to 2. - A re-run is triggered, causing the second form to be displayed.
Instead, submitting the first form sets the new st.session_state["step"] = 2
, but the first form button needs to be clicked a second time in order to display the second form.
Can someone help me understand what is happening here? Thanks!
Reprex code
import streamlit as st
def init():
if "init" not in st.session_state:
st.session_state["init"] = True
st.session_state["step"] = 1
st.session_state["animal"] = None
st.session_state["color"] = None
def choose_animal():
with st.form(key="form_animal", clear_on_submit=False):
st.header("Step 1")
# Problem 1: this way of setting state is lost when widget disappears
#animal = st.selectbox(label="Choose your favorite animal", key="animal",
# options=["Cat", "Dog", "Zebrafish"])
# In order to preserve state after widget disappears,
# st.session_state needs to be manually set to widget value
animal = st.selectbox(label="Choose your favorite animal",
options=["Cat", "Dog", "Zebrafish"])
if st.form_submit_button("Confirm choice"):
st.session_state["animal"] = animal
# Problem 2: the session state is set here
# but the script does not re-run until the button is clicked a second time
st.session_state["step"] = 2
def choose_color():
with st.form(key="form_color", clear_on_submit=False):
st.header("Step 2")
color = st.selectbox(label="Choose your favorite color",
options=["Azure", "Blue", "Cobalt", "Cyan", "Indigo", "Lapis lazuli"])
if st.form_submit_button("Confirm choice"):
st.session_state["step"] = 3
st.session_state["color"] = color
def get_result(animal: str, color: str):
return f"Congratulations! You chose the {color.lower()} {animal.lower()}"
def main():
init()
if st.session_state["step"]==1:
choose_animal()
elif st.session_state["step"]==2:
choose_color()
else:
result = get_result(animal=st.session_state["animal"], color=st.session_state["color"])
st.write(result)
st.write(st.session_state)
main()
st.write(st.session_state)