Adding a select all / deselect all button to act on a list of checkboxes

Hi,

I am using streamlit to plot some data in Python. My dataframe has 3 columns – A, B, and C. I have a checkbox corresponding to each column of the data. By default I want all 3 columns to be plotted. Is there a way to add a select all / deselect all button, such that if pressed will check (or uncheck) all of the checkboxes depending on the state?

Essentially, there are 3 states:

  1. all of the checkboxes are checked
  2. none of the checkboxes are checked
  3. some of the checkboxes are checked

If I am in state 1), I want the button to deselect all of the checkboxes . If I am in state 2) or 3), I want the button to select all of the checkboxes.

Any help is very much appreciated!

Thank you,
Blake

Does it make any difference, there are only 3 checkboxes.

Here is a sample code.

import streamlit as st
from streamlit import session_state as ss

if 'msg' not in ss:
    ss.msg = ''


def change():
    # If check all
    if ss.sel == 'Check All':
        # We can only check all if at least one is not checked.
        if not all(v for v in [ss.cb1, ss.cb2, ss.cb3]):
            ss.cb1 = True
            ss.cb2 = True
            ss.cb3 = True
            ss.sel = 'None'  # reset to None to be ready again
            ss.msg = ''
        else:
            ss.msg = 'You cannot check all if all are already checked.'
    # Else if uncheck all
    elif ss.sel == 'Uncheck All':
        # We can only uncheck all if all are checked already.
        if all(v for v in [ss.cb1, ss.cb2, ss.cb3]):
            ss.cb1 = False
            ss.cb2 = False
            ss.cb3 = False
            ss.sel = 'None'  # reset to None to be ready again
            ss.msg = ''
        else:
            ss.msg = 'You cannot uncheck all if all are not yet checked.'


st.checkbox('cb1', key='cb1')
st.checkbox('cb2', key='cb2')
st.checkbox('cb3', key='cb3')

st.divider()

st.write(f'cb1: {ss.cb1}')
st.write(f'cb2: {ss.cb2}')
st.write(f'cb3: {ss.cb3}')

st.divider()

st.radio(
    'Select',
    ['None', 'Check All', 'Uncheck All'],
    horizontal=True,
    key='sel',
    on_change=change
)
if ss.msg:
    st.error(ss.msg)

Sample test 1 output

Sample test 2 output

Version 2, this is more intelligent.

import streamlit as st
from streamlit import session_state as ss

if 'msg' not in ss:
    ss.msg = ''


def ind_change():
    """Whenever there are changes to individual cb."""
    ss.sel = 'None'
    ss.msg = ''


def change():
    # If check all
    if ss.sel == 'Check All':
        # We can only check all if at least one is not checked.
        if not all(v for v in [ss.cb1, ss.cb2, ss.cb3]):
            ss.cb1 = True
            ss.cb2 = True
            ss.cb3 = True
            ss.sel = 'None'  # reset to None to be ready again
            ss.msg = ''
        else:
            ss.msg = 'You cannot check all if all are already checked.'
    # Else if uncheck all
    elif ss.sel == 'Uncheck All':
        # We can only uncheck all if all are checked already.
        if all(v for v in [ss.cb1, ss.cb2, ss.cb3]):
            ss.cb1 = False
            ss.cb2 = False
            ss.cb3 = False
            ss.sel = 'None'  # reset to None to be ready again
            ss.msg = ''
        else:
            ss.msg = 'You cannot uncheck all if all are not yet checked.'
    else:
        ss.msg = ''


st.checkbox('cb1', key='cb1', on_change=ind_change)
st.checkbox('cb2', key='cb2', on_change=ind_change)
st.checkbox('cb3', key='cb3', on_change=ind_change)

st.divider()

st.write(f'cb1: {ss.cb1}')
st.write(f'cb2: {ss.cb2}')
st.write(f'cb3: {ss.cb3}')

st.divider()

st.radio(
    'Select',
    ['None', 'Check All', 'Uncheck All'],
    horizontal=True,
    key='sel',
    on_change=change
)
if ss.msg:
    st.error(ss.msg)