R

ReflexKR

Reflex公式ドキュメント

コンポーネント工房:Reflexライブラリ100

·

講座の概要

レイアウト

·

Box

·

Flex

·

Stack

·

Grid

·

Container

·

Section

·

Center

·

Spacer

·

Separator

·

Card

·

Inset

·

Aspect Ratio

·

Fragment

タイポグラフィ

·

Text

·

Heading

·

Link

·

Code

·

Markdown

·

Blockquote

·

Quote

·

Strong

·

Em

·

Kbd

フォーム

·

Button

·

Input

·

Text Area

·

Checkbox

·

Switch

·

Radio Group

·

Select

·

Slider

·

Form

·

Upload

データ表示

·

Badge

·

Avatar

·

Icon

·

Callout

·

List

·

Data List

·

Code Block

·

Progress

·

Spinner

·

Scroll Area

·

Moment

開閉と切り替え

·

Tabs

·

Accordion

·

Segmented Control

オーバーレイ

·

Tooltip

·

Popover

·

Hover Card

·

Dialog

·

Alert Dialog

·

Drawer

·

Dropdown Menu

·

Context Menu

·

Toast

動的レンダリング

·

Cond

·

Match

·

Foreach

·

Auto Scroll

メディア

·

Image

·

Audio

·

Video

表とデータグリッド

·

Table

·

Data Table

·

Data Editor

チャート

·

Area Chart

·

Bar Chart

·

Line Chart

·

Composed Chart

·

Pie Chart

·

Radar Chart

·

Radial Bar Chart

·

Scatter Chart

·

Funnel Chart

·

Treemap

·

Sankey Chart

·

Error Bar

チャートの部品

·

Axis

·

Cartesian Grid

·

Chart Tooltip

·

Legend

·

Label

·

Reference

·

Brush

ほかのチャートライブラリ

·

Plotly

·

Pyplot

HTML要素

·

HTML

·

HTML Text

·

HTML Layout

·

HTML Forms

·

HTML Media

·

HTML Tables

·

SVG

そのほかの道具

·

Theme

·

Skeleton

·

Clipboard

·

Html Embed

·

Script

·

Memo

コンポーネント工房:Reflexライブラリ100
フォーム

Select

rx.selectrx.select.rootrx.select.triggerrx.select.contentrx.select.grouprx.select.labelrx.select.itemrx.select.separator

公式ドキュメント

工房の注文書

商品一覧の上にカテゴリーのドロップダウンを付けてください。選んだカテゴリーの商品だけが下に表示されるようにしてください。

rx.selectはクリックすると開くリストから値をひとつ選ぶドロップダウンです。Radix UI の上に作られていてキーボードでも選べ、デスクトップでもモバイルでも同じように動きます。リストをひとつ渡すだけで、ボタンとリストが一緒に作られます。

  • 選択肢が5個より多くて縦のスペースを節約したいとき、決められたリストから必ずひとつ選ばせたいときに使います。
  • 選択肢が少ないなら、一目で見渡せる Radio Group のほうが向いています。複数選ぶなら Checkbox のグループ、自由に入力させるなら Input を使います。
  • グループの見出し、区切り線、選択肢をひとつだけ無効にするといった細かい構成は、低水準 API(rx.select.root …)で行います。
rx.select(["apple", "grape", "pear"])

プロパティを変えてみる

placeholderは何も選んでいないときだけ表示されます。position="popper"ならリストはボタンの下に開き、"item-aligned"(既定)なら選んだ選択肢がボタンの位置に重なるように開きます。

プロパティを変えてみる

placeholder

variant

size

color

radius

position

high_contrast

disabled

rx.select(["apple", "grape", "pear"], placeholder="Choose a fruit...", variant="surface", size="2", color_scheme="indigo", radius="medium", position="item-aligned", high_contrast=False, disabled=False)
variant には、ボタンの枠線までなくす ghost もあります。high_contrast は開いたリストのコントラストを上げます。
プロパティ値既定値用途
最初の引数(items)文字列のリスト / Var必須選択肢のリスト。値と表示される文字が同じ
value文字列 / Varなし制御する選択値(on_changeと併用)
default_value文字列なし最初に一度だけ選ぶ値
placeholder文字列""選ぶ前にボタンに表示される案内文
label文字列なし開いたリストの一番上に出るグループの見出し
variant"classic" "surface" "soft" "ghost""surface"ボタンの見た目
size"1" ~ "3""2"大きさ
color_scheme, radius, high_contrastテーマの値色、ボタンの角の丸み、リストのコントラスト
position"item-aligned" "popper""item-aligned"リストの開き方。ダイアログの中では popper
widthCSS の長さなしボタンの幅
open / default_openTrue / FalseFalseリストの開閉を制御 / 最初から開いておく
name, required, disabledフォーム送信時の名前、選ばないと送信できない、無効化
on_changeイベント別の選択肢を選んだとき。値(文字列)を渡す
on_open_changeイベントリストが開閉したとき。True/Falseを渡す

選んだ値に追従する

いちばんよくある使い方です。valueに State 変数を、on_changeにその変数を更新するハンドラーをつなぎます。選択は常に State の値を表示するので、アプリのどこで値を変えてもドロップダウンが追従します。

You selected:

apple
class SelectFruitState(rx.State):
    selected_fruit: str = "apple"

    @rx.event
    def update_fruit(self, value: str):
        self.selected_fruit = value


rx.hstack(
    rx.select(
        ["apple", "grape", "pear"],
        value=SelectFruitState.selected_fruit,
        on_change=SelectFruitState.update_fruit,
    ),
    rx.text("You selected:"),
    rx.badge(SelectFruitState.selected_fruit),
    align="center",
    spacing="3",
)

初期値、案内文、無効化

State が不要で最初の選択だけ決めたいならdefault_valueを使います(非制御)。フォーム送信時にだけ値が必要なら、これで十分です。空の状態から始めて選択を促したいなら、default_valueを外してplaceholderを渡します。disabled=Trueなら薄く表示され、開きません。

rx.flex(
    rx.select(["apple", "grape", "pear"], default_value="grape"),
    rx.select(["apple", "grape", "pear"], placeholder="Choose a fruit..."),
    rx.select(["apple", "grape", "pear"], default_value="apple", disabled=True),
    spacing="3",
    wrap="wrap",
)

State から来る選択肢

選択肢はたいていデータベースや API から来ます。リストの代わりに State のリスト Var を渡せば、リストが変わったときに選択肢も変わります。内部ではrx.foreachで選択肢を作ります。

3 options

import random


class SelectDynamicState(rx.State):
    options: list[str] = ["apple", "grape", "pear"]
    selected: str = "apple"

    @rx.event
    def set_selected(self, value: str):
        self.selected = value

    @rx.event
    def randomize(self):
        self.selected = random.choice(self.options)

    @rx.event
    def add_option(self):
        new_options = ["banana", "orange", "mango", "kiwi", "cherry"]
        available = [o for o in new_options if o not in self.options]
        if available:
            self.options = self.options + [available[0]]

    @rx.event
    def reset_options(self):
        self.options = ["apple", "grape", "pear"]
        self.selected = "apple"


rx.vstack(
    rx.select(
        SelectDynamicState.options,
        value=SelectDynamicState.selected,
        on_change=SelectDynamicState.set_selected,
    ),
    rx.hstack(
        rx.button("Pick Random", on_click=SelectDynamicState.randomize, size="1"),
        rx.button("Add Option", on_click=SelectDynamicState.add_option, size="1", variant="soft"),
        rx.button("Reset", on_click=SelectDynamicState.reset_options, size="1", variant="soft", color_scheme="gray"),
    ),
    rx.text(SelectDynamicState.options.length(), " options", size="1", color_scheme="gray"),
)

フォームで使う

nameが送信データのキーになり、required=Trueなら選ぶまで送信されません。選ばれていない select は空の値("")として入ります。

Favorite fruit

Quantity

Results:

{}
class SelectFormState(rx.State):
    form_data: dict = {}

    @rx.event
    def handle_submit(self, form_data: dict):
        self.form_data = form_data


rx.card(
    rx.vstack(
        rx.form.root(
            rx.vstack(
                rx.text("Favorite fruit", size="2"),
                rx.select(["apple", "grape", "pear"], name="fruit", placeholder="Pick one", required=True),
                rx.text("Quantity", size="2"),
                rx.select(["1", "2", "3", "4", "5"], name="quantity", default_value="1"),
                rx.button("Submit Order", type="submit"),
                spacing="2",
                align="stretch",
            ),
            on_submit=SelectFormState.handle_submit,
            reset_on_submit=True,
        ),
        rx.divider(),
        rx.hstack(rx.text("Results:", weight="bold"), rx.badge(SelectFormState.form_data.to_string())),
        spacing="3",
    ),
    width="320px",
)

表示名と値を分ける

高水準のrx.selectは値と表示される文字が同じです。ユーザー名を表示して ID を使いたいなら、公式ドキュメントのように計算変数で名前から ID を引けます。

Selected user ID: user_001

class SelectUserState(rx.State):
    users: dict[str, str] = {
        "user_001": "Alice Johnson",
        "user_002": "Bob Smith",
        "user_003": "Carol Davis",
    }
    selected_name: str = "Alice Johnson"

    @rx.var
    def user_names(self) -> list[str]:
        return list(self.users.values())

    @rx.var
    def selected_id(self) -> str:
        for uid, name in self.users.items():
            if name == self.selected_name:
                return uid
        return ""

    @rx.event
    def set_user(self, name: str):
        self.selected_name = name


rx.vstack(
    rx.select(
        SelectUserState.user_names,
        value=SelectUserState.selected_name,
        on_change=SelectUserState.set_user,
    ),
    rx.text("Selected user ID: ", rx.code(SelectUserState.selected_id), size="2"),
)

ドロップダウンの中で直接分けたいなら、低水準 API でrx.select.item("表示する文字", value="値")のように書きます。on_changeはvalueを渡します。

value = kr

class SelectCountryState(rx.State):
    code: str = "kr"

    @rx.event
    def set_code(self, value: str):
        self.code = value


rx.hstack(
    rx.select.root(
        rx.select.trigger(),
        rx.select.content(
            rx.select.item("Korea", value="kr"),
            rx.select.item("Japan", value="jp"),
            rx.select.item("Germany", value="de"),
        ),
        value=SelectCountryState.code,
        on_change=SelectCountryState.set_code,
    ),
    rx.text("value = ", rx.code(SelectCountryState.code), size="2"),
    align="center",
)

ダイアログの中で

Dialog のように画面の上に浮かぶコンテナの中ではposition="popper"を渡します。そうするとリストがダイアログに切り取られず、ボタンのすぐ下に開きます。

rx.dialog.root(
    rx.dialog.trigger(rx.button("Open Dialog")),
    rx.dialog.content(
        rx.dialog.title("Pick a fruit"),
        rx.vstack(
            rx.select(["apple", "grape", "pear"], position="popper", default_value="apple"),
            rx.dialog.close(rx.button("Close", variant="soft")),
            spacing="3",
        ),
        max_width="320px",
    ),
)

開閉したとき:on_open_change

on_open_changeはリストが開くとTrue、閉じるとFalseを渡します。開いたときにデータを先読みしたり、回数を数えたりするのに使います。

Open count: 0

Closed
class SelectOpenState(rx.State):
    is_open: bool = False
    open_count: int = 0

    @rx.event
    def on_toggle(self, is_open: bool):
        self.is_open = is_open
        if is_open:
            self.open_count += 1


rx.vstack(
    rx.select(["apple", "grape", "pear"], default_value="apple", on_open_change=SelectOpenState.on_toggle),
    rx.hstack(
        rx.text("Open count: ", SelectOpenState.open_count, size="2"),
        rx.cond(
            SelectOpenState.is_open,
            rx.badge("Open", color_scheme="green"),
            rx.badge("Closed", color_scheme="gray"),
        ),
        align="center",
    ),
)

低水準 API:子コンポーネント

高水準のrx.selectは、下の部品を代わりに組み立ててくれるものです。自分で組み立てれば、グループの見出しや区切り線を入れたり、選択肢をひとつだけ無効にしたりできます。

部品役割主なプロパティ
rx.select.root全体と選択値value default_value on_change open default_open on_open_change name required disabled size
rx.select.triggerクリックするボタンplaceholder variant color_scheme radius
rx.select.content開いたリストposition side side_offset align align_offset variant("solid" "soft") color_scheme high_contrast
rx.select.group選択肢のグループ
rx.select.labelグループの見出し
rx.select.item選択肢ひとつvalue(必須) disabled
rx.select.separator区切り線

rx.select.contentにはon_escape_key_down、on_pointer_down_outside、on_close_auto_focusイベントもあります。下は、グループが2つ、区切り線、無効な選択肢(Grape)があるリストです。

rx.select.root(
    rx.select.trigger(placeholder="Pick a food", variant="soft", radius="full"),
    rx.select.content(
        rx.select.group(
            rx.select.label("Fruits"),
            rx.select.item("Orange", value="orange"),
            rx.select.item("Apple", value="apple"),
            rx.select.item("Grape", value="grape", disabled=True),
        ),
        rx.select.separator(),
        rx.select.group(
            rx.select.label("Vegetables"),
            rx.select.item("Carrot", value="carrot"),
            rx.select.item("Potato", value="potato"),
        ),
        position="popper",
        side="bottom",
        side_offset=6,
        variant="soft",
        color_scheme="green",
    ),
    size="2",
)

完全に制御する:value と open

低水準の root でも、value + on_changeで選択を、open + on_open_changeで開閉を State が持てます。ボタンで選択を変えたりリストを開いたりできます。on_open_changeがopenを更新しないと、ボタンを押してもリストが開きも閉じもしないので注意してください。

フォームでは root のnameがキー、選んだ item のvalueが値になります。

class SelectControlState(rx.State):
    value: str = "apple"
    open: bool = False

    @rx.event
    def set_value(self, value: str):
        self.value = value

    @rx.event
    def set_open(self, value: bool):
        self.open = value

    @rx.event
    def next_fruit(self):
        fruits = ["apple", "grape", "pear"]
        self.value = fruits[(fruits.index(self.value) + 1) % 3]


rx.vstack(
    rx.select.root(
        rx.select.trigger(),
        rx.select.content(
            rx.select.item("apple", value="apple"),
            rx.select.item("grape", value="grape"),
            rx.select.item("pear", value="pear"),
        ),
        value=SelectControlState.value,
        on_change=SelectControlState.set_value,
        open=SelectControlState.open,
        on_open_change=SelectControlState.set_open,
    ),
    rx.hstack(
        rx.button("Next value", on_click=SelectControlState.next_fruit, size="1", variant="soft"),
        rx.button("Open menu", on_click=SelectControlState.set_open(True), size="1", variant="soft"),
    ),
)

連動する選択

前の select の値によって後ろの select の選択肢が変わるパターンです(地域 → 国)。地域を変えると、ハンドラーが国もその地域の最初の国に合わせるので、後ろの select が存在しない値を指すことはありません。

class SelectCascadeState(rx.State):
    regions: dict[str, list[str]] = {
        "North America": ["USA", "Canada", "Mexico"],
        "Europe": ["UK", "France", "Germany"],
        "Asia": ["Japan", "Korea", "Singapore"],
    }
    region: str = "North America"
    country: str = "USA"

    @rx.event
    def set_region(self, value: str):
        self.region = value
        self.country = self.regions[value][0]

    @rx.event
    def set_country(self, value: str):
        self.country = value

    @rx.var
    def region_names(self) -> list[str]:
        return list(self.regions.keys())

    @rx.var
    def countries(self) -> list[str]:
        return self.regions.get(self.region, [])


rx.hstack(
    rx.select(SelectCascadeState.region_names, value=SelectCascadeState.region, on_change=SelectCascadeState.set_region),
    rx.select(SelectCascadeState.countries, value=SelectCascadeState.country, on_change=SelectCascadeState.set_country),
    spacing="3",
    wrap="wrap",
)

注文書を仕上げる

select が下に表示するデータを決める、フィルターのパターンです。計算変数filtered_itemsが選んだカテゴリーの商品だけを返し、rx.foreachがカードとして並べます。labelは開いたリストの一番上にグループの見出しとして表示されます。

MacBook Pro
Dell XPS
class SelectFilterState(rx.State):
    all_items: list[dict[str, str]] = [
        {"name": "MacBook Pro", "category": "laptops"},
        {"name": "Dell XPS", "category": "laptops"},
        {"name": "iPhone 15", "category": "phones"},
        {"name": "Pixel 8", "category": "phones"},
        {"name": "iPad Air", "category": "tablets"},
        {"name": "Galaxy Tab", "category": "tablets"},
    ]
    category: str = "laptops"

    @rx.event
    def set_category(self, value: str):
        self.category = value

    @rx.var
    def filtered_items(self) -> list[dict[str, str]]:
        return [i for i in self.all_items if i["category"] == self.category]


rx.vstack(
    rx.select(
        ["laptops", "phones", "tablets"],
        value=SelectFilterState.category,
        on_change=SelectFilterState.set_category,
        label="Category",
    ),
    rx.foreach(SelectFilterState.filtered_items, lambda item: rx.card(item["name"], width="100%")),
    spacing="3",
    width="280px",
)

工房ノート

  • rx.select([選択肢...]) で作り、value + on_change で State と結ぶ。初期値だけなら default_value。

  • 選ぶ前の案内は placeholder、ダイアログの中では position="popper"。

  • 選択肢を State のリストで渡すと、リストがデータに追従する。

  • 表示する文字と値が違う、あるいはグループ・区切り線・無効な選択肢が必要なら root · trigger · content · group · label · item · separator。

  • on_open_change は開く(True)/ 閉じる(False)。open で直接制御するなら、ハンドラーが open を更新すること。

← 前へ

フォーム · Radio Group

次へ →

フォーム · Slider

新しい授業・講座のお知らせを受け取る

この講座に授業が追加されたり、続きの講座が公開されたりしたらメールでお知らせします。

収集項目:メールアドレス・目的:この講座の新しい授業・公開のお知らせ・保有期間:解除のご依頼まで。他の目的には使わず、第三者にも提供しません。お知らせメールに返信いただければすぐに削除します。

質問と回答

この回について気になることを書き込んでください。すべての言語のページの質問がここに集まります。

リンクや書式なしで、そのままの文字で表示されます。

R

ReflexKR

触って学ぶPythonとReflex。すべての例はReflex 0.10.0で実際に動かして確認しています。

ReflexKRはバナー広告なし・無料で運営しています。役に立ったら、コーヒー一杯で応援してください。 ☕ コーヒーで応援する

アフィリエイトと支援について
한국어English日本語简体中文EspañolDeutsch

© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0

Built with Reflex