Skip to content

๐Ÿƒย ย Card Selector

Submitted by Arnaud Miribel

Summary

Card-based option picker with icons, titles, and descriptions โ€” like st.segmented_control but bigger.

Functions

card_selector

Display a card-based selector for richer option picking.

Each option renders as a bordered card with an optional icon, title, and description. Like st.segmented_control but designed for choices that need more visual real-estate.

Parameters:

Name Type Description Default
items Sequence[CardItem]

Sequence of card items. Each is a dict with optional icon, title, and description string keys. Icons support :material/name: format, emojis, or plain text.

required
selection_mode Literal['single', 'multi']

"single" (default) allows one selection. "multi" allows toggling multiple cards.

'single'
default int | list[int] | None

Initially selected index (single mode) or list of indices (multi mode). None means nothing selected.

None
key str | None

Unique key for this component instance.

None

Returns:

Type Description
int | list[int] | None

In single mode: the selected index (int) or None.

int | list[int] | None

In multi mode: a list of selected indices.

Source code in src/streamlit_extras/card_selector/__init__.py
@extra
def card_selector(
    items: Sequence[CardItem],
    *,
    selection_mode: Literal["single", "multi"] = "single",
    default: int | list[int] | None = None,
    key: str | None = None,
) -> int | list[int] | None:
    """Display a card-based selector for richer option picking.

    Each option renders as a bordered card with an optional icon, title,
    and description. Like ``st.segmented_control`` but designed for
    choices that need more visual real-estate.

    Args:
        items: Sequence of card items. Each is a dict with optional
            ``icon``, ``title``, and ``description`` string keys.
            Icons support ``:material/name:`` format, emojis, or plain text.
        selection_mode: ``"single"`` (default) allows one selection.
            ``"multi"`` allows toggling multiple cards.
        default: Initially selected index (single mode) or list of
            indices (multi mode). ``None`` means nothing selected.
        key: Unique key for this component instance.

    Returns:
        In single mode: the selected index (``int``) or ``None``.
        In multi mode: a list of selected indices.
    """
    resolved_key = key or "card_selector_default"
    component_state = st.session_state.get(resolved_key, {})

    if "selected" in component_state:
        selected: list[int] = component_state["selected"]
    elif default is not None:
        selected = [default] if isinstance(default, int) else list(default)
    else:
        selected = []

    _CARD_SELECTOR_COMPONENT(
        data={
            "items": [dict(i) for i in items],
            "selected": selected,
            "selection_mode": selection_mode,
        },
        key=resolved_key,
        default={"selected": selected},
        on_selected_change=lambda: None,
    )

    component_state = st.session_state.get(resolved_key, {})
    current: list[int] = component_state.get("selected", selected)

    if selection_mode == "single":
        return current[0] if current else None
    return current

Import:

from streamlit_extras.card_selector import card_selector # (1)!
  1. You should add this to the top of your .py file ๐Ÿ› 

Examples

example_basic

def example_basic() -> None:
    selected = card_selector(
        [
            dict(
                icon=":material/cloud:",
                title="Cloud",
                description="Deploy to a managed cloud service",
            ),
            dict(
                icon=":material/computer:",
                title="Local",
                description="Run on your own machine",
            ),
            dict(
                icon=":material/dns:",
                title="On-Prem",
                description="Host in your data center",
            ),
        ],
        key="demo_basic",
    )
    if selected is not None:
        st.write(f"You picked option **{selected}**")

example_multi_select

def example_multi_select() -> None:
    selected = card_selector(
        [
            dict(icon="๐Ÿ“Š", title="Analytics", description="Usage dashboards"),
            dict(icon="๐Ÿ””", title="Alerts", description="Email & Slack notifications"),
            dict(icon="๐Ÿ”’", title="Security", description="SSO & audit logs"),
            dict(icon="๐Ÿš€", title="Performance", description="Caching & CDN"),
        ],
        selection_mode="multi",
        key="demo_multi",
    )
    st.write(f"Selected: **{selected}**")

example_minimal

def example_minimal() -> None:
    selected = card_selector(
        [
            dict(icon=":material/rocket_launch:", title="Starter"),
            dict(icon=":material/star:", title="Pro"),
            dict(icon=":material/diamond:", title="Enterprise"),
        ],
        key="demo_minimal",
    )
    if selected is not None:
        st.write(f"Plan: **{['Starter', 'Pro', 'Enterprise'][selected]}**")

example_long_text

def example_long_text() -> None:
    selected = card_selector(
        [
            dict(
                icon="๐Ÿ“Š",
                title="Analytics",
                description="Usage dashboards for anything related to what users are using you know.",
            ),
            dict(icon="๐Ÿ””", title="Alerts", description="Email & Slack notifications"),
            dict(icon="๐Ÿ”’", title="Security", description="SSO & audit logs"),
            dict(icon="๐Ÿš€", title="Performance", description="Caching & CDN"),
        ],
        selection_mode="multi",
        key="demo_long_text",
    )
    st.write(f"Selected: **{selected}**")