Form input validation in multi-page Streamlit app

I have a multi-page Streamlit app with a form that stores input data in st.session_state, and displays it on the next page. I want to add input validation and display a warning message for missing input below the respective field using a placeholder (st.empty()). The issue is that I have to click the form button twice to proceed after adding missing input:

import streamlit as st

if 'page' not in st.session_state: st.session_state.page = 0
def nextPage(): st.session_state.page += 1
def firstPage(): st.session_state.page = 0

def main_page(name_error_message=None):
    st.markdown("# Main page")
    with st.form(key='main_page'):
        st.session_state.name = st.text_input("Enter your name (required)")
        name_error_message = st.empty()
        submit_button = st.form_submit_button(label='Next')
        if submit_button:
            if st.session_state.name == '':
                name_error_message.error("Please enter your name")
            else:
                nextPage()

def page2():
    st.markdown(f"# Hi {st.session_state.name}!")
    st.button("First page", on_click=firstPage)

page_names_to_funcs = {
    0: main_page,
    1: page2,
}

page_names_to_funcs[st.session_state.page]()

It seems that Streamlit first needs a run to remove the error message and only then can proceed to the next page. Any solutions or workarounds?

Try adding st.experimental_rerun() at the end of your nextPage() function. Alternatively, you could wrap the entire functionality you want from the form submit button inside a function and use that function as a callback in an on_click argument to the button.

The problem if I understand it correctly is that all the code in the form executes before the form values are sent back, so your if statement hits the button’s False state first, then all values are updated, then if you click again you hit the True state from the previous click.

Thanks, adding st.experimental_rerun() did the trick! I tried wrapping everything in a callback function before, but that broke populating the st.empty() container.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.