Select

Custom select component.

Installation

Copy the following code into your app directory.

uv

buridan add component select
Usage
from components.ui.select import select
Anatomy

Use the following composition to build a Select

select.root( select.trigger( select.value(), select.icon(), ), select.portal( select.positioner( select.popup( select.group( select.group_label(), select.item( select.item_text(), select.item_indicator(), ), ), select.separator(), ), ), ), )
Examples
Align Item

Use align_item_with_trigger on select.positioner() to control whether the selected item aligns with the trigger. When true (default), the popup positions so the selected item appears over the trigger. When false, the popup aligns to the trigger edge.

Align Item

Toggle to align the item with the trigger.

import reflex as rx
from reflex.experimental import ClientStateVar

from components.icons.hugeicon import hi
from components.ui.select import select
from components.ui.switch import switch

align_with_item_trigger = ClientStateVar.create("align_with_item_trigger", False)

items = ["apple", "banana", "orange", "grape", "blueberry", "pineapple"]


def select_align_with_items():

    return rx.el.div(
        rx.el.div(
            rx.el.div(
                rx.el.p("Align Item", class_name="font-medium text-foreground"),
                rx.el.p(
                    "Toggle to align the item with the trigger.",
                    class_name="text-muted-foreground",
                ),
                class_name="flex flex-col gap-y-2 text-sm",
            ),
            switch.root(
                switch.thumb(),
                on_checked_change=align_with_item_trigger.set_value(
                    ~align_with_item_trigger.value
                ),
            ),
            class_name="flex flex-row items-start justify-between w-full",
        ),
        select.root(
            select.trigger(
                select.value(),
                select.icon(hi("ArrowDown01Icon", classs_name="size-4")),
                class_name="w-full flex items-center justify-between group",
            ),
            select.portal(
                select.positioner(
                    select.popup(
                        select.group(
                            select.group_label("Fruit"),
                            *[
                                select.item(
                                    select.item_text(fruit.capitalize()),
                                    select.item_indicator(
                                        hi("Tick02Icon", class_name="size-4")
                                    ),
                                    value=fruit,
                                    class_name="w-full !max-w-sm flex flex-row items-center justify-between",
                                )
                                for fruit in items
                            ],
                        ),
                    ),
                    side_offset=4,
                    align_item_with_trigger=align_with_item_trigger.value,
                ),
            ),
            name="example_select",
            default_value="blueberry",
        ),
        class_name="flex flex-col gap-y-4 max-w-sm",
    )
Groups

Use select.group to organize items into sections, select.group_label to label each section, and select.separator to visually divide groups.

from components.icons.hugeicon import hi
from components.ui.select import select


def select_groups():
    fruits = [
        {"label": "Apple", "value": "apple"},
        {"label": "Banana", "value": "banana"},
        {"label": "Blueberry", "value": "blueberry"},
    ]

    vegetables = [
        {"label": "Carrot", "value": "carrot"},
        {"label": "Broccoli", "value": "broccoli"},
        {"label": "Spinach", "value": "spinach"},
    ]

    return select.root(
        select.trigger(
            select.value(),
            select.icon(
                # hi("ArrowDown01Icon", classs_name="size-4"),
            ),
            class_name="w-full max-w-48 flex items-center justify-between",
        ),
        select.portal(
            select.positioner(
                select.popup(
                    select.group(
                        select.group_label("Fruits"),
                        *[
                            select.item(
                                select.item_text(item["label"]),
                                select.item_indicator(
                                    # hi("Tick02Icon", class_name="size-4")
                                ),
                                value=item["value"],
                                class_name="flex flex-row items-center justify-between",
                            )
                            for item in fruits
                        ],
                    ),
                    select.separator(),
                    select.group(
                        select.group_label("Vegetables"),
                        *[
                            select.item(
                                select.item_text(item["label"]),
                                select.item_indicator(
                                    # hi("Tick02Icon", class_name="size-4")
                                ),
                                value=item["value"],
                                class_name="flex flex-row items-center justify-between",
                            )
                            for item in vegetables
                        ],
                    ),
                ),
            ),
        ),
        items=[*fruits, *vegetables],
        name="select_groups",
        default_value="banana",
    )
Scrollable

Use select.scroll_up_arrow and select.scroll_down_arrow to provide navigation controls for scrolling through long lists of select items within the dropdown.

from components.ui.select import select


def select_with_scroll_arrows():
    north_america = [
        {"label": "Eastern Standard Time", "value": "est"},
        {"label": "Central Standard Time", "value": "cst"},
        {"label": "Mountain Standard Time", "value": "mst"},
        {"label": "Pacific Standard Time", "value": "pst"},
        {"label": "Alaska Standard Time", "value": "akst"},
        {"label": "Hawaii Standard Time", "value": "hst"},
    ]

    europe_africa = [
        {"label": "Greenwich Mean Time", "value": "gmt"},
        {"label": "Central European Time", "value": "cet"},
        {"label": "Eastern European Time", "value": "eet"},
        {"label": "Central Africa Time", "value": "cat"},
        {"label": "East Africa Time", "value": "eat"},
    ]

    asia = [
        {"label": "Moscow Time", "value": "msk"},
        {"label": "India Standard Time", "value": "ist"},
        {"label": "China Standard Time", "value": "cst_china"},
        {"label": "Japan Standard Time", "value": "jst"},
    ]

    return select.root(
        select.trigger(
            select.value(),
            select.icon(),
            class_name="w-full max-w-64 flex items-center justify-between",
        ),
        select.portal(
            select.positioner(
                select.popup(
                    select.scroll_up_arrow(),
                    select.list(
                        select.group(
                            select.group_label("North America"),
                            *[
                                select.item(
                                    select.item_text(i["label"]),
                                    select.item_indicator(),
                                    value=i["value"],
                                )
                                for i in north_america
                            ],
                        ),
                        select.group(
                            select.group_label("Europe & Africa"),
                            *[
                                select.item(
                                    select.item_text(i["label"]),
                                    select.item_indicator(),
                                    value=i["value"],
                                )
                                for i in europe_africa
                            ],
                        ),
                        select.group(
                            select.group_label("Asia"),
                            *[
                                select.item(
                                    select.item_text(i["label"]),
                                    select.item_indicator(),
                                    value=i["value"],
                                )
                                for i in asia
                            ],
                        ),
                        class_name="max-h-64 overflow-y-auto",
                    ),
                    select.scroll_down_arrow(),
                ),
            ),
        ),
        items=[
            {"label": "Select timezone", "value": None},
            *north_america,
            *europe_africa,
            *asia,
        ],
        name="timezone_select",
        default_value="est",
    )