I am developing an app where I need to have a “st.form_submit_button”. My app has 3 columns inside the st.form context manager. Once I am done with everything, at the very end, I have to submit my results. So, I use st.form_submit_button outside of the third column; otherwise, I get an error to use st.form_submit_button inside the st.form. This is the layout of my codes:
c1, c2, c3 = st.columns([1, 1, 1], gap="large")
with st.form("main form", clear_on_submit=True):
with c1:
##### some stuff #####
with c2:
##### some stuff #####
with c3:
##### some stuff #####
if st.form_submit_button('"Submit"):
#### Some function ####
Once I do this, Streamlit positions the “Submit” button at the lower left (right below the column 1. However, I’d like to move the “Submit” button to lower right (at the button of the third col). The following shows the UI of my app:
Just put the submit within c3, and if you want it on the right of c3 then create additional columns under c3 and adjust their widths to make the button jam against the right edge. (Note you can only nest columns to two (or three?) levels.)
Move the column creation into the form so that the form holds the parent context.
import streamlit as st # 🎈 streamlit development
with st.form("main form", clear_on_submit=True):
c1, c2, c3 = st.columns([1, 1, 1], gap="large")
with c1:
with st.container(border=True):
st.write("##### C1 #####")
st.image("https://picsum.photos/200/300")
with c2:
with st.container(border=True):
st.write("##### C2 #####")
st.image("https://picsum.photos/200/300")
with c3:
with st.container(border=True):
st.write("##### C3 #####")
st.image("https://picsum.photos/200/300")
c3_1, c3_2 = st.columns([1, 1])
with c3_2:
submitted = st.form_submit_button("Submit")
if submitted:
st.write("##### some stuff #####")
Thanks for your explanation. However, I ran into another problem. My st.form_submit_button function has on_change argumnet, that is, st.form_submit_button(“Submit”, on_change )
Also, I have another on_change argument in of the widgets under c2 column in the above code, so if I do what you said, Streamlit complains that the on_change cannot be in two places if I am using st.form_submit_button, So I get the following error:
streamlit.errors.StreamlitAPIException: With forms, callbacks can only be defined on the st.form_submit_button. Defining callbacks on other widgets inside a form is not allowed.
Unfortunately, it is very difficult to merge these two on_change functions under one widget, i.e., st.form_submit_button(“Submit”, on_change ).
The point about a form is that its widget values are not available to the rest of the app until the form is submitted. That’s why only the submit callback is allowed. Within that callback you can retrieve the form’s widgets’ values using each widget’s key, which you must define.
If that still doesn’t solve your problem, and you must have callbacks on the widget change events, then you can simulate a “form” using a container to hold the widgets (so you get a nice border) and a standard button for the submit. That’s the structure used in the above link.