Select a color with a selectbox

Hello, I am trying to figure out a way to select a color from a predetermined color schema.

  • Solution 1 - Color picker : As far as I know, st.color_picker doesn’t allow restricting the colors to a specified selection.
  • Solution 2 - Selectbox: This is the solution that I currently use, and I think matches my requirements the most, but it’s not user-friendly at all, since the user needs to do their selection based on the color number, not the color. (see screenshot)

I tried to play a bit with the labels of the selectbox, to at least display the color in the label once selected, but it wasn’t relliable on color change or color removing. It could help the user for sure, but it’s still far from ideal since the user would need to select the color to see it.

If anyone has had a similar issue / requirement I’ll gladly take on advices. Maybe there is a widget that can do that but I didn’t find it.

Hello ! I don’t know if it is a satisfying option for you but you can use CSS and the n-th child property ! Here is a working example, do not hesitate to ask for more precise use cases:

import streamlit as st


def generate_css_for_options(colors: list) -> str:
    css = "<style>"
    for i, color in enumerate(colors):
        css += (
            f"""ul[data-testid="stSelectboxVirtualDropdown"] li[role="option"]:nth-child({i + 1})"""
            + "{"
            + f"background-color: {color['code']}; color: {color['text_color']};"
            + "}"
        )
    return f"{css}</style>"


def generate_css_for_box(color_name: str) -> str:
    css = "<style>"
    for color in colors:
        if color["name"] == color_name:
            css += (
                """div[data-baseweb="select"] div {"""
                + f"background-color: {color['code']}; color: {color['text_color']};"
                + "}"
            )
            return f"{css}</style>"


colors = [
    {"code": "#101B58", "name": "Penn Blue", "text_color": "#FFFFFF"},
    {"code": "#45296C", "name": "Tekhelet", "text_color": "#FFFFFF"},
    {"code": "#793780", "name": "Eminence", "text_color": "#FFFFFF"},
    {"code": "#AD4594", "name": "Fandango", "text_color": "#FFFFFF"},
    {"code": "#E153A8", "name": "Brilliant Rose", "text_color": "#FFFFFF"},
    {"code": "#F0A998", "name": "Melon", "text_color": "#FFFFFF"},
    {"code": "#F8D490", "name": "Sunset", "text_color": "#000000"},
    {"code": "#FFFF88", "name": "Icterine", "text_color": "#000000"},
]

st.markdown(generate_css_for_options(colors), unsafe_allow_html=True)
options = [color["name"] for color in colors]
st.markdown(
    generate_css_for_box(st.session_state.get("color_selected", colors[0])),
    unsafe_allow_html=True,
)
st.selectbox(label="Choose a color", options=options, key="color_selected")
1 Like

Thanks a lot, that works quite well, but it ends up coloring all the other selectboxes no ? Or am I missing something ?
I think I read somewhere that streamlit is planning to put the key in the css, so that should allow this code to work only for specified selectboxes haha.

You could create PNG images and display them inline. It’s not supported yet for Selectbox options (though there is an open PR for it). However, you could use st.pills.

  1. Create colored squares as PNG files.
  2. Save them in a /static directory for your project. (I named them by their color in this example, “f27148.png” for example.)
  3. Enabled static hosting to serve them.
import streamlit as st

APP_URL = "http://localhost:8501"
colors = ["f27148","faac4f","8acb88","88c4f2","6a93d9","8ec641","b0b7c3"]

def format_color(color):
    return f"![{color}]({APP_URL}/app/static/{color}.png) #{color}"

z = st.pills("Color", options=colors, format_func=format_color, key="4")
1 Like

Yes after some tests the solution has two major issues :

  • All the other selectboxes are colored. To fix this, you could create a unique combination of containers and columns that encapsulates the selectbox you want to color and make a more precise CSS selector. This works well but is not very flexible especially in large applications.
  • If you have many colors and scroll down, some options will not be rendered anymore and thus the nth-child property will not work as wanted.

If you want, I can help you on the first option ! Or if it is really needed you could also create a custom component !

1 Like

That’s perfect, thank you very much !