How do you change the contents of a form based on radio buttons?

I wish to show different fields in a form, depending on what values a radio button takes. The radio button must be shown after some of the text entry fields and before some of the others.

This runs, but the radio button gets put at the bottom of the page:

form = st.form("form", border = False)
first = form.text_input("First")
second = form.text_input("Second")

show_questions = st.radio("Show questions", ("No", "Yes"))

if show_questions == "Yes":
    third = form.text_input("Third")
    fourth = form.text_input("Fourth")

submit_button = form.form_submit_button("Submit")

I do not want that. I want the radio buttons to show up between the second and third text inputs.

This runs, but changing the value in the radio button does not change what fields are chosen.

form = st.form("form", border = False)
first = form.text_input("First")
second = form.text_input("Second")

show_questions = form.radio("Show questions", ("No", "Yes"))

if show_questions == "Yes":
    third = form.text_input("Third")
    fourth = form.text_input("Fourth")

submit_button = form.form_submit_button("Submit")

I do not want that. Changing what value is selected in the radio button must immediately change what fields are displayed.

This runs, but changing any text box makes the page rerun:

first = st.text_input("First")
second = st.text_input("Second")

show_questions = st.radio("Show questions", ("No", "Yes"))

if show_questions == "Yes":
    third = st.text_input("Third")
    fourth = st.text_input("Fourth")

submit_button = st.button("Submit")

I do not want that. Typing in the text entry boxes must not rerun the page.

This causes an error saying ā€œMissing Submit Button: This form has no submit button, which means that user interactions will never be sent to your Streamlit app. To create a submit button, use the st.form_submit_button() function.ā€

form_top_half = st.form("form_top_half ", border = False)
first = form_top_half.text_input("First")
second = form_top_half.text_input("Second")

show_questions = st.radio("Show questions", ("No", "Yes"))

form_bottom_half = st.form("form_bottom_half", border = False)

if show_questions == "Yes":
    third = form_bottom_half.text_input("Third")
    fourth = form_bottom_half.text_input("Fourth")

submit_button = form_bottom_half.form_submit_button("Submit")

But I do not want to have a separate submit button for the top half of the form.

What should I do? How can I have a radio button in the middle of the form, that changes the contents of the form when toggled, while still using forms to avoid rerunning the page when the text in a text box is changed?

@plokmijn12345, this thread probably answers your question:

1 Like

Thank you, but I donā€™t think that works. Like, if you put things in empty elements, they will change when clicked, but you still canā€™t create a field in the form itself that depends on them.

Perhaps I misunderstood, is not this :point_down: the behavior you are after?

changing_form

1 Like

How are you doing that? I have something like:

with st.form("form"):
    space_for_selecting_use_case = st.empty()

    if use_case == "complex":
        additional_input = st.text_input("Additional Input")

with space_for_selecting_use_case:
    use_case = st.radio(
        label = "Select your use case.",
        options = ("simple", "complex")
    )

I then get an error of ā€œcannot access local variable ā€˜use_caseā€™ where it is not associated with a valueā€ when checking if use_case == "complex".

In the provided example, radio_option was only accessed in a different empty element, whose contents were defined after the section initializing radio_option itself. How would you access the value of radio_option in an if-statement in the form itself?

You are trying to use a variable that has not been declared yet. The use of containers helps with placing elements in the page in an arbitrary order, but the code still runs from top to bottom.

The only change you need is to place the st.empty containers inside the st.form and put the if logic outside the form, where the empty containers are actually filled up.

Code for the screen recording from before:
import streamlit as st

with st.form("form"):
    first = st.text_input("First")
    second = st.text_input("Second")

    placeholder_radio = st.empty()
    placeholder_additional_inputs = st.empty()

    submit_button = st.form_submit_button("Submit")

with placeholder_radio:
    show_questions = st.radio("Show questions", ("No", "Yes"))

with placeholder_additional_inputs.container():
    if show_questions == "Yes":
        third = st.text_input("Third")
        fourth = st.text_input("Fourth")

if submit_button:
    "**You submitted:**"
    if show_questions == "Yes":
        st.write(first, second, third, fourth)
    else:
        st.write(first, second)
1 Like

Thank you! I did not know that using an st.container() within an st.empty() element would do the job. Adding more st.empty() containers at the bottom would have worked, but things in them would rerun the page when changed. How did you know that using an st.container() within an st.empty() would allow you to create fields that can see the status of something in an earlier st.empty(), but not rerun the page when changed?

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