Search code examples
pythonfrontendwidgetstreamlit

Streamlit multiple Checkboxes with one allowed Selection


I want to make multiple checkboxes in streamlit like in this image below.

Screenshot Checkboxes

But I want the behavior, that just on checkbox can be selected. That means, if a checkbox is selected and you select another one that cancels out the first selection.

I also tried it out with st.radio, but the problem there is that I can't have no selection and it doesn't fulfill my use case.


Solution

  • The simplest could be to use st.radio with another radio Show All or Show Nothing

    With st.checkbox you could use on_change to run code which set False on other checkboxes.

    Every checkbox needs unique key, and it has to send this key to on_check.

    It also need to keep all keys on list - to use it late to uncheck all other checkboxes


    Minimal working code:

    import streamlit as st
    
    def on_change_checkbox(current_key):
        #print('current_key:', current_key)
    
        # uncheck all checkboxes except current
        for key in checkbox_keys:
            if key != current_key:
                st.session_state[key] = False
    
    checkbox_keys = []
    
    key = 'cb pdf'
    st.checkbox('Select PDF', key=key, on_change=on_change_checkbox, args=(key,))
    checkbox_keys.append(key)
    
    key = 'cb database'
    st.checkbox('Select Database', key=key, on_change=on_change_checkbox, args=(key,))
    checkbox_keys.append(key)
    
    key = 'cb something else'
    st.checkbox('Select Something Else', key=key, on_change=on_change_checkbox, args=(key,))
    checkbox_keys.append(key)
    

    Example which use dictionary with lists to group checkboxes

    #!/usr/bin/env python3
    
    """
    # author: Bartlomiej "furas" Burek (https://blog.furas.pl)
    # date: 2024.06.20
    # [python - Streamlit multiple Checkboxes with one allowed Selection - Stack Overflow](https://stackoverflow.com/questions/78647325/streamlit-multiple-checkboxes-with-one-allowed-selection/78648360#78648360)
    """
    
    import streamlit as st
    
    def on_change_checkbox(current_key, group):
        print('current_key:', current_key, group)
    
        # uncheck all checkboxes except current
        for key in checkbox_keys[group]:
            if key != current_key:
                st.session_state[key] = False
    
    checkbox_keys = {}
    
    # ----
    
    st.text('Source')
    
    checkbox_keys['Source'] = []
    
    key = 'cb source pdf'
    st.checkbox('Select PDF', key=key, on_change=on_change_checkbox, args=(key, 'Source'))
    checkbox_keys['Source'].append(key)
    
    key = 'cb source database'
    st.checkbox('Select Database', key=key, on_change=on_change_checkbox, args=(key, 'Source'))
    checkbox_keys['Source'].append(key)
    
    key = 'cb source something else'
    st.checkbox('Select Something Else', key=key, on_change=on_change_checkbox, args=(key, 'Source'))
    checkbox_keys['Source'].append(key)
    
    # ----
    
    st.text('Target')
    
    checkbox_keys['Target'] = []
    
    key = 'cb target pdf'
    st.checkbox('Select PDF', key=key, on_change=on_change_checkbox, args=(key, 'Target'))
    checkbox_keys['Target'].append(key)
    
    key = 'cb target database'
    st.checkbox('Select Database', key=key, on_change=on_change_checkbox, args=(key, 'Target'))
    checkbox_keys['Target'].append(key)
    
    key = 'cb target something else'
    st.checkbox('Select Something Else', key=key, on_change=on_change_checkbox, args=(key, 'Target'))
    checkbox_keys['Target'].append(key)
    

    Screenshot Streamlit


    With st.radio you may only add button which assigns None and this will clear selection.

    import streamlit as st
    
    def clear_radio(current_key):
        #print('current_key:', current_key)
    
        # uncheck radio
        st.session_state[current_key] = None
    
    
    key = 'r select'
    st.radio('Select:', key=key, index=None, options=['Select PDF', 'Select Database', 'Select Something Else'])
    st.button('Clear', on_click=clear_radio, args=(key,))