Multi-select “All” option in Streamlit
When using the Streamlit multiselect widget, we often need a way to select all items and with a widget with many options, this can be a lot of work. This simple solution uses a callback function and a few session state variables to adapt the behavior of this widget to allow an “All” option at the beginning of our options list.
For this example, we need a list of 11 items. Note that our list begins with -1. I’ll use this negative number on my formatting function to inject the “All Option.” I’ll also declare a session state variable called“max_selections” and initially set it to the length of our list.
available_options = [i for i in range(-1, 10)]
if "max_selections" not in st.session_state:
st.session_state["max_selections"] = len(available_options)
Callback Function
This callback function will be bound to the on_change parameter of our multiselect widget. Callback functions execute before the rest of the code executes on a triggered event. Read more about these here. Because callback functions use session state, I will evaluate whether “selected_options,” which belongs to the “key” parameter of the multiselect widget, exists in the app session state. This evaluation will prevent an uninitialized variable error. Then, I will evaluate if -1, a value bound to the “All” option, exists in the list of items selected in the multiselect widget. If true, I will set my “selected_options” to only the first item on the list and set the “max_selections” variable to 1 to prevent more options from being selected. If false, it will set the “max_selections” variable back to the length of the source list.
def options_select():
if "selected_options" in st.session_state:
if -1 in st.session_state["selected_options"]:
st.session_state["selected_options"] = [available_options[0]]
st.session_state["max_selections"] = 1
else:
st.session_state["max_selections"] = len(available_options)
Widget
Now, the multiselect widget will use a few parameters:
- Label
- options: Set to the list we created in the first step.
- key: This will create a session state variable for this widget.
- max_selections: This value is programmatically adjusted in the first step and the callback function.
- on_change: This will invoke the callback function every time there is a new change on this widget.
- format_func: For this example, we’re using a lambda function to format the items on our widget without changing the output. In this parameter, it’s when -1 becomes “All”.
st.multiselect(
label="Select an Option",
options=available_options,
key="selected_options",
max_selections=st.session_state["max_selections"],
on_change=options_select,
format_func=lambda x: "All" if x == -1 else f"Option {x}",
)
Display the output
I use a simple “write” widget with an IF statement to determine whether to display all but -1 or the selected options.
st.write(
available_options[1:]
if st.session_state["max_selections"] == 1
else st.session_state["selected_options"]
)
Results
Full code
import streamlit as st
def options_select():
if "selected_options" in st.session_state:
if -1 in st.session_state["selected_options"]:
st.session_state["selected_options"] = [available_options[0]]
st.session_state["max_selections"] = 1
else:
st.session_state["max_selections"] = len(available_options)
available_options = [i for i in range(-1, 10)]
if "max_selections" not in st.session_state:
st.session_state["max_selections"] = len(available_options)
st.multiselect(
label="Select an Option",
options=available_options,
key="selected_options",
max_selections=st.session_state["max_selections"],
on_change=options_select,
format_func=lambda x: "All" if x == -1 else f"Option {x}",
)
st.write(
available_options[1:]
if st.session_state["max_selections"] == 1
else st.session_state["selected_options"]
)