How (not) to create a responsive form in Streamlit?
Diving into the limitations of st.form, or when does st.form not perform as responsively as expected?
How (not) to create a responsive form in Streamlit?
Diving into the limitations of st.form, or when does st.form not perform as responsively as expected?
With the addition of st.form¹, Streamlit’s user experience has improved significantly. While I was building an app recently, I discovered an “anti-pattern” regarding the use of callback functions with inputs from st.form. When the form is submitted, the most recent values are not updated yet, and you need to press the button twice. I’m not the first to encounter this (see here, here or here). That’s why I’m sharing this story for future reference and to help others learn from it.

Image created by magicstudio
When doesn’t it work?
If you create a basic form and want to use the results in your callback function, in the setup below you’ll encounter that the variables are not updated before the submit button is pressed. The MWE shown below will show you that your selection is not shown when you press the button the first time. Only on the second press of the button is the updated value shown.
import streamlit as st
with st.form("form"):
s = st.segmented_control("Slide", options=range(5))
st.form_submit_button("Submit", on_click=st.write, args=(s, ))
So why doesn’t it work? Apparently when storing the output of widgets in variables these are not updated when the submit button is pressed.²’³’⁴
A simple change to using the Session State will make it work.
import streamlit as st
def callback(key: str):
st.write(st.session_state[key])
with st.form("form"):
st.segmented_control("Slide", options=range(5), key="s")
st.form_submit_button("Submit", on_click=callback, args=("s"))
What works?
To show what works I’ve look at the options/choices you can make when created a form:
- Using the with statement or the direct assignment;
- Using variables or keys for the output;
- Using a callback function, via
on_click, or a function called on anif-statement³.
This gives eight possible combinations to make a form. In this app I showcase how all combinations work as long as the widget state is not stored in a variable together with on_click. In essence, the options for forms mentioned in the documentation³’⁵ work.
This story is my way to share my coding experience and the lessons I learned, and to document my solutions. All claps, comments, and highlights are appreciated, as well as sharing the story. For more code and my other links see: https://github.com/UnicornOnAzur/.
[1] https://discuss.streamlit.io/t/introducing-submit-button-and-forms/12401
[2] https://discuss.streamlit.io/t/date-input-not-working-on-form-submit/34740
[3] https://docs.streamlit.io/develop/api-reference/execution-flow/st.form
[5] https://docs.streamlit.io/develop/concepts/architecture/forms
메타데이터
- post_id
- d487bb0836a1
- slug
- how-not-to-create-a-responsive-form-in-streamlit-d487bb0836a1
- url
- https://medium.com/top-python-libraries/how-not-to-create-a-responsive-form-in-streamlit-d487bb0836a1
- canonical_url
- https://medium.com/top-python-libraries/how-not-to-create-a-responsive-form-in-streamlit-d487bb0836a1
- author_url
- https://medium.com/@unicornonazur
- status
- ok
- fetched_at
- 2026-08-03 23:05:12