"Hidden" widgets not properly initialised

Hi everyone,

I am having some troubles with the initialization of widgets using the session state.
In the given example below, the first selectobox is properly initialised using the value stored in the session_state. However, if the toggle is toggled, the initial status of the second selectbox is incorrect.
How can I fix that?

import streamlit as st

# Initialize session state values if not already set
if 'value1' not in st.session_state:
    st.session_state['value1'] = 'A'
if 'value2' not in st.session_state:
    st.session_state['value2'] = 'A'

# Create the toggle button
toggle = st.toggle('Toggle')

# Render the first selectbox
st.selectbox('Selectbox 1', ['B', 'D', 'A', 'C'], key='value1')

# Render the second selectbox based on the toggle state
if toggle:
    st.selectbox('Selectbox 2', ['B', 'D', 'A', 'C'], key='value2')

# Optional: Output the current session state for debugging
st.write(st.session_state)

Streamlit == 1.36
Python == 3.12

Hi,
I thing there is a missunderstanding with how session state work.

  1. The session state is initialized correctly, but the selectbox widgets are overwriting these values.
  2. When you use a key parameter in a Streamlit widget that matches a session state key, the widget will both read from and write to that session state value.
  3. In this case, the selectboxes with key='value1' and key='value2' are overwriting the initial session state values each time the script runs.
  4. The selectboxes default to the first option (‘B’) if no index is specified, which is why you’re not seeing the initial ‘A’ values preserved.

To fix this, you should either:

  1. Use the index parameter in the selectboxes to set their initial values based on the session state, or
  2. Use different keys for the selectboxes that don’t conflict with your session state variables.

It will work :

        # Initialize session state values if not already set
        if 'value1' not in st.session_state:
            st.session_state['value1'] = 2
        if 'value2' not in st.session_state:
            st.session_state['value2'] = 2

        # Create the toggle button
        toggle = st.toggle('Toggle')

        # Render the first selectbox
        st.selectbox('Selectbox 1', ['B', 'D', 'A', 'C'], key='1', index=st.session_state['value1'])

        # Render the second selectbox based on the toggle state
        if toggle:
            st.selectbox('Selectbox 2', ['B', 'D', 'A', 'C'], key='2', index=st.session_state['value2'])

        # Optional: Output the current session state for debugging
        st.write(st.session_state)

a nice video to understand session state :slight_smile:

Thanks for the reply!
What is confusing is that the first selectbox is properly initialised via the session state and does display ‘A’ on the first run which mean the widget is initialising itself using the value stored in the session state (?!). However, the second selectbox is not properly initialised like the first one while they have both been initialised exactly the same way :frowning:

The key issue is that when the second selectbox appears for the first time (when you activate the toggle), Streamlit creates a new widget instance. At this point, it doesn’t use the value from the session state but instead uses the first value in the options list as the default value, which is ‘B’ in this case.

little update for a better coding :

        list_choice = ['B', 'D', 'A', 'C']
        st.selectbox('Selectbox 2', list_choice, key='value2',
                     index=list_choice.index(st.session_state['value2']))

This ensures that even when the selectbox is rendered for the first time, it will use the correct value from the session state. (And it avoid any overwritting problem).

1 Like

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