Updating radio inside a form

Hello everyone,
I’m blocking on something with Streamlit.
I have a multiselect then 2 radios, the 2 radios are kinda connected between them
Without using form, streamling is running everytime I’m changing the radio or if I am doing something in the multiselect.
So I tried to use a form for all of these, but when I’m changing my radio, nothing is happening, it’s stucked

My actual code:

import streamlit as st

options_players = st.multiselect(
    'Compare players (max 7)',
    df_pos.player_slug.unique(), max_selections=7)

col1, col2, col3 = st.columns(3)
option = st.radio('Select :',
                  ['Season',
                   'Year',
                   'Lasts'],
                  horizontal=True)
if option == "Season":
      option_calendar = st.radio('Select :',
                               ['2022-2023',
                                '2021-2022',
                                '2020-2021'],
                               horizontal=True)
if option == "Year":
    option_calendar = st.radio('Select :',
                           ['2023',
                            '2022',
                            '2021'],
                          horizontal=True)
option_lasts = False
if option == "Lasts":
    option_calendar = False
    option_lasts = st.radio('Select :',
                            ['L40',
                            'L15',
                            'L5'],
                           horizontal=True)


search_button = st.button('Search')

The form I tried :


import streamlit as st

form = st.form("my_form")

options_players = form.multiselect(
    'Compare players (max 7)',
    df_pos.player_slug.unique(), max_selections=7)

col1, col2, col3 = form.columns(3)
option = form.radio('Select :',
                  ['Season',
                   'Year',
                   'Lasts'],
                  horizontal=True)
if option == "Season":
      option_calendar = form.radio('Select :',
                               ['2022-2023',
                                '2021-2022',
                                '2020-2021'],
                               horizontal=True)
if option == "Year":
    option_calendar = form.radio('Select :',
                           ['2023',
                            '2022',
                            '2021'],
                          horizontal=True)
option_lasts = False
if option == "Lasts":
    option_calendar = False
    option_lasts = form.radio('Select :',
                            ['L40',
                            'L15',
                            'L5'],
                           horizontal=True)

search_button = form.form_submit_button("Search")

What would be the best way to do that (if it’s possible) ?

Thanks for your help.

Hi @KoinKoin and welcome to Streamlit!

This is expected behavior. Streamlit will rerun every time a widget is changed unless that widget is in a form. Any widget inside a form will not create a change until that form is submitted.

If you need a widget to make an immediate change to something, then that widget needs to be outside of a form. Programmatic changes can’t occur without Streamlit rerunning. In particular, if a widget (A) is meant to update another widget (B), then widget A should be outside a form. However, widget B could be inside a form if it’s not itself a source to update other widgets.

That’s what I thought… So if I want a form, I would need my 9 radios available immediately…
By the way, I think it’s not possible, but is there a way to format the st.radio ? Like having my 9 radios in a 3 x 3 shape ?

Widgets can change if they are defined outside the form but are positioned inside the form using a placeholder like st.empty. Not sure if that is expected behavior or not, but looks like a feature to me :smiley:

dynamicForm

Code:

import streamlit as st

with st.form("myform"):

    "### A form"

    # These exist within the form but won't wait for the submit button
    placeholder_for_radio = st.empty()
    placeholder_for_selectbox = st.empty()
    
    # Other components actually wait for the submit button
    number = st.number_input("Add a number", 0, 10, 1, 1)
    
    submit_button = st.form_submit_button("Submit!")

# Create radio and selectbox outside the form
with placeholder_for_radio:
    radio_option = st.radio("`st.radio`", ["Plants", "Animals"], horizontal=True)
    
with placeholder_for_selectbox:
    options = dict(
        Plants = ["🌱", "🌿", "🪴"],
        Animals = ["🐇", "🦔", "🐖"]
    )
    selection = st.selectbox("`st.selectbox`", options=options[radio_option])


# This is just to show the app behavior
with st.sidebar:

    "#### `st.radio` and `st.selectbox` don't wait for `st.form_submit_button` to be clicked to update their value"
    st.info(f"`st.radio` = *{radio_option}*")
    st.info(f"`st.selectbox` = *{selection}*")

    "#### But the other components within `st.form` do wait for `st.form_submit_button` to be clicked to update their value"
    st.info(f"{number}")

if submit_button:
    st.info(f"""
            Form submitted with 
            - `{radio_option = }`
            - `{selection = }` 
            - `{number = }`""")

else:
    st.warning("`st.form_submit_button` has not been clicked yet")
3 Likes

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