Streamlit Button Disable/Enable

How do I properly enable/disable a button? I’m attempting to enable button_c when button_a clicked; disable button_c when button_b clicked. Default is disabled. As far as I understand, this is in session_state. Below code is my attempt, not working.

import streamlit as st

if 'but_a' not in st.session_state:
    st.session_state.disabled = True

    
button_a = st.button('a', key='but_a')

button_b = st.button('b', key='but_b')

button_c = st.button('c', key='but_c', disabled=st.session_state.disabled)

st.write(button_a, button_b, button_c)

if button_a:
    st.write("clicked A")
    st.session_state.disabled = False

if button_b:
    st.write('clicked B')
    st.session_state.disabled = True

What is happening, IIUC, is that as soon as you click the button (and, crucialy, before st.session_state.disabled is updated), the app is rerun. Then the buttons are drawn again (using the old value in st.session_state.disabled) and only after that is st.session_state.disabled assigned the new value, but a this point the buttons have been already drawn. As a result, you need to click twice to redraw everything and see the changes.

The solution is assigning to st.session_state.disabled before calling st.button, but you have to make it work even when the buttons do not exist yet (first run).

if st.session_state.get("but_a", False):
    st.session_state.disabled = False
elif st.session_state.get("but_b", False):
    st.session_state.disabled = True

button_a = st.button('a', key='but_a')
button_b = st.button('b', key='but_b')
button_c = st.button('c', key='but_c', disabled=st.session_state.get("disabled", True))

Using a callback works too:

def disable(b):
    st.session_state["disabled"] = b

button_a = st.button('a', key='but_a', on_click=disable, args=(False,))
button_b = st.button('b', key='but_b', on_click=disable, args=(True,))
button_c = st.button('c', key='but_c', disabled=st.session_state.get("disabled", True))
3 Likes