Forms
In Streamlit, a form is a container used to group widgets together in a way that prevents them from being updated on each script rerun. Forms are useful for situations where you want the user to fill out multiple input fields (like text inputs, sliders, checkboxes) but only process the data once the user submits the form by clicking a button.
You create a form by using st.form():
import streamlit as st
# Define a form
with st.form("my_form"):
# Add form elements
name = st.text_input("Enter your name")
age = st.slider("Select your age", 18, 100)
# Submit button
submit_button = st.form_submit_button("Submit")
# When the form is submitted, process the data
if submit_button:
st.write(f"Hello {name}, you are {age} years old.")Submit form
Outside of a form, when a user interacts with widgets that accept keyed input (such as st.number_input, st.text_input, and st.text_area), the value is immediately processed and triggers a rerun when the user clicks away or tabs out of the widget. Additionally, pressing Enter while the cursor is active in these widgets will also trigger the value update.
Inside a form, however, submission behavior is slightly different. A user can submit a form by clicking the Submit button within the form or by pressing Enter while their cursor is active in any widget that accepts keyed input (like st.number_input or st.text_input). For st.text_area, submission requires pressing Ctrl+Enter (Windows/Linux) or ⌘+Enter (Mac). This behavior ensures that the entire form is submitted at once, rather than triggering immediate reruns for each individual widget.

Processing form submissions
Changes made within a form are not immediately sent to the Python backend; they are only processed when the form is submitted. And the only widget inside a form that can have a callback function is the st.form_submit_button. If you need to execute a process using newly submitted values, you have three primary patterns to follow:
Execute the Process After the Form Submission
If you need to execute a one-time process after a form submission, you can condition that process on the st.form_submit_button. The process will be triggered after the form is submitted, and the output can be displayed in any location relative to the form by using containers like columns.
import streamlit as st
col1,col2 = st.columns([1,2])
col1.title('Sum:')
with st.form('addition'):
a = st.number_input('a')
b = st.number_input('b')
submit = st.form_submit_button('add')
if submit:
col2.title(f'{a+b:.2f}')Use a callback with session state
You can use a callback to execute a process before the page reruns. In this case, the callback runs when the form is submitted, allowing you to process newly submitted values immediately.
WARNING
When handling newly updated values in a callback, avoid passing them directly via args or kwargs. Instead, assign a key to the widgets and retrieve their values from Session State within the callback function.
import streamlit as st
if 'sum' not in st.session_state:
st.session_state.sum = ''
def sum():
result = st.session_state.a + st.session_state.b
st.session_state.sum = result
col1,col2 = st.columns(2)
col1.title('Sum:')
if isinstance(st.session_state.sum, float):
col2.title(f'{st.session_state.sum:.2f}')
with st.form('addition'):
st.number_input('a', key = 'a')
st.number_input('b', key = 'b')
st.form_submit_button('add', on_click=sum)Use st.rerun
If your process needs to update content displayed above the form, you can trigger an additional page rerun using st.rerun. However, this approach is less resource-efficient and might be less desirable compared to the above options.
import streamlit as st
if 'sum' not in st.session_state:
st.session_state.sum = ''
col1,col2 = st.columns(2)
col1.title('Sum:')
if isinstance(st.session_state.sum, float):
col2.title(f'{st.session_state.sum:.2f}')
with st.form('addition'):
a = st.number_input('a')
b = st.number_input('b')
submit = st.form_submit_button('add')
# The value of st.session_state.sum is updated at the end of the script rerun,
# so the displayed value at the top in col2 does not show the new sum. Trigger
# a second rerun when the form is submitted to update the value above.
st.session_state.sum = a + b
if submit:
st.rerun()Limitations
- Every form must contain a
st.form_submit_button. st.buttonandst.download_buttoncannot be used in a form.- Forms (
st.form) cannot be nested inside other forms. - Callback functions can only be assigned to
st.form_submit_button; no other widgets within the form can have callback functions. - Interdependent widgets within a form may not behave as expected. For example, if
widget2depends on the value ofwidget1and both are inside a form,widget2will only update after the form is submitted, not immediately upon changingwidget1.
