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
オーバーレイ

Context Menu

rx.context_menu.rootrx.context_menu.triggerrx.context_menu.contentrx.context_menu.itemrx.context_menu.separatorrx.context_menu.subrx.context_menu.sub_triggerrx.context_menu.sub_content

公式ドキュメント

工房の注文書

ファイル一覧でファイル名を右クリックすると、スター・複製・削除を選べるメニューがその場に出るようにしてください。

コンテキストメニューは、要素を右クリック(タッチ画面では長押し)するとマウスの位置に出るメニューです。ファイル、表の行、画像など、「これに対して」できる操作をまとめておくときに使います。パーツはドロップダウンメニューと同じです。

  • context_menu.root:すべてのパーツを包みます。
  • context_menu.trigger:右クリックを受け付ける要素を包みます。
  • context_menu.content:開いたときに出るパネルです。
  • context_menu.item:項目1つです。shortcutでショートカットキーの文字を添えます。
  • context_menu.separator:項目のあいだの線です。
  • context_menu.sub:サブメニューを包みます。その中にcontext_menu.sub_triggerとcontext_menu.sub_contentを置きます。
rx.context_menu.root(
    rx.context_menu.trigger(
        rx.button("Right click me"),
    ),
    rx.context_menu.content(
        rx.context_menu.item("Edit", shortcut="⌘ E"),
        rx.context_menu.item("Duplicate", shortcut="⌘ D"),
        rx.context_menu.separator(),
        rx.context_menu.item("Archive", shortcut="⌘ N"),
        rx.context_menu.sub(
            rx.context_menu.sub_trigger("More"),
            rx.context_menu.sub_content(
                rx.context_menu.item("Move to project…"),
                rx.context_menu.item("Move to folder…"),
                rx.context_menu.separator(),
                rx.context_menu.item("Advanced options…"),
            ),
        ),
        rx.context_menu.separator(),
        rx.context_menu.item("Share"),
        rx.context_menu.item("Add to favorites"),
        rx.context_menu.separator(),
        rx.context_menu.item("Delete", shortcut="⌘ ⌫", color="red"),
    ),
)

プロパティを変えてみる

点線の枠を右クリックしてみてください。メニューパネルの見た目はcontentに、右クリックを止めるdisabledはtriggerに指定します。disabledをオンにすると、ブラウザ標準の右クリックメニューが出ます。

プロパティを変えてみる

Right-click here

variant

size

color

high_contrast

disabled

modal

rx.context_menu.root(
    rx.context_menu.trigger(
        rx.center(
            rx.text("Right-click here", size="2", color_scheme="gray"),
            width="260px",
            height="110px",
            border=f"2px dashed {rx.color('gray', 7)}",
            border_radius="8px",
        ),
        disabled=False,
    ),
    rx.context_menu.content(
        rx.context_menu.item("Copy", shortcut="⌘ C"),
        rx.context_menu.item("Paste", shortcut="⌘ V"),
        rx.context_menu.separator(),
        rx.context_menu.item("Delete", shortcut="⌘ ⌫", color_scheme="red"),
        variant="solid",
        size="2",
        color_scheme="indigo",
        high_contrast=False,
    ),
    modal=True,
)
コンテキストメニューはマウスを押した位置で開くので、side・alignよりもvariant・size・color_schemeを主に変えます。
パーツプロパティ値用途
rootmodalTrue / False開いているあいだ外側の操作を止める
rooton_open_changeイベント開閉したとき。新しい開閉値(bool)を渡す
triggerdisabledTrue / False右クリックで開かないようにする
contentvariant · size"solid" "soft" · "1" "2"強調のしかた、大きさ
contentcolor_scheme · high_contrast色の名前 · bool項目を塗る色、コントラスト
contentloop · side · align · side_offset · align_offset-キーボードでの循環、位置の微調整
contentavoid_collisions · collision_padding · sticky · hide_when_detached-画面の端の扱い
itemshortcut · color_scheme · disabled · text_value-ショートカットの文字、色、選べなくする、文字検索用テキスト
itemon_selectイベント項目を選んだとき
subopen · default_open · on_open_change-サブメニューの開閉
sub_triggerdisabled · text_value-サブメニューを開く項目
sub_contentloop · side_offset · align_offsetなど-サブパネルの位置

ドロップダウンメニューと違って、rootにはopenがありません。メニューは右クリックでしか開きません。contentとsub_contentにはon_escape_key_down、on_pointer_down_outside、on_focus_outside、on_interact_outsideのイベントがあります。

項目はcontentの直下に

context_menu.itemはcontext_menu.contentの直接の子でなければなりません。条件によって項目を切り替えようとしてrx.vstackのような箱で項目をまとめると、メニューが項目を認識できなくなります。公式ドキュメントが禁止している形は次のとおりです。

rx.context_menu.content(
    rx.cond(
        State.count % 2 == 0,
        rx.vstack(  # 箱でまとめてはいけない
            rx.context_menu.item("Even Option 1"),
            rx.context_menu.item("Even Option 2"),
        ),
        rx.vstack(
            rx.context_menu.item("Odd Option A"),
            rx.context_menu.item("Odd Option B"),
        ),
    )
)

Stateに応じて項目を変えたいなら、リストを計算変数にしてrx.foreachで項目を直接描きます。rx.foreachは余計な箱を作りません。下でcountボタンを押してから、もう一度右クリックしてみてください。

Selected: none

class ContextMenuOptionsState(rx.State):
    count: int = 0
    selected: str = "none"

    @rx.event
    def increment(self):
        self.count += 1

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

    @rx.var
    def options(self) -> list[str]:
        if self.count % 2 == 0:
            return ["Even Option 1", "Even Option 2", "Even Option 3"]
        return ["Odd Option A", "Odd Option B", "Odd Option C"]


rx.flex(
    rx.context_menu.root(
        rx.context_menu.trigger(rx.button("Right click me")),
        rx.context_menu.content(
            rx.foreach(
                ContextMenuOptionsState.options,
                lambda option: rx.context_menu.item(option, on_select=ContextMenuOptionsState.set_selected(option)),
            ),
        ),
    ),
    rx.button("count = ", ContextMenuOptionsState.count, variant="soft", on_click=ContextMenuOptionsState.increment),
    rx.text("Selected: ", ContextMenuOptionsState.selected, size="2"),
    spacing="3",
    align="center",
    wrap="wrap",
)

開閉したとき:on_open_change

context_menu.rootのon_open_changeは、開くとTrue、閉じるとFalseを渡します。

Opened or closed: 0 times

Context menu open: no

class ContextMenuEventState(rx.State):
    num_opens: int = 0
    opened: bool = False

    @rx.event
    def count_opens(self, value: bool):
        self.opened = value
        self.num_opens += 1


rx.flex(
    rx.text("Opened or closed: ", ContextMenuEventState.num_opens, " times"),
    rx.text("Context menu open: ", rx.cond(ContextMenuEventState.opened, "yes", "no")),
    rx.context_menu.root(
        rx.context_menu.trigger(rx.button("Right click me", variant="soft")),
        rx.context_menu.content(
            rx.context_menu.item("Copy"),
            rx.context_menu.item("Paste"),
        ),
        on_open_change=ContextMenuEventState.count_opens,
    ),
    direction="column",
    spacing="3",
    align="start",
)

メニューからダイアログを開く

ドロップダウンメニューと同じく、ダイアログをメニュー項目の中に入れると、メニューが閉じるときに一緒に消えてしまいます。ダイアログはメニューの外に置き、項目はStateの値を変えるだけにします。各ダイアログはその値が自分の名前のときに開き、閉じるときはon_open_changeが値を空にします。下のアイコンを右クリックしてみてください。

class ContextMenuDialogState(rx.State):
    which_dialog_open: str = ""

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

    @rx.event
    def delete(self):
        yield rx.toast("Deleted item")

    @rx.event
    def save_settings(self):
        yield rx.toast("Saved settings")


rx.vstack(
    rx.context_menu.root(
        rx.context_menu.trigger(rx.icon_button(rx.icon("ellipsis-vertical"), variant="soft", aria_label="Right-click for menu")),
        rx.context_menu.content(
            rx.context_menu.item("Delete", on_click=ContextMenuDialogState.set_which_dialog_open("delete")),
            rx.context_menu.item("Settings", on_click=ContextMenuDialogState.set_which_dialog_open("settings")),
        ),
    ),
    rx.cond(
        ContextMenuDialogState.which_dialog_open,
        rx.text(ContextMenuDialogState.which_dialog_open, " dialog is open"),
    ),
    rx.alert_dialog.root(
        rx.alert_dialog.content(
            rx.alert_dialog.title("Are you Sure?"),
            rx.alert_dialog.description(
                "This action cannot be undone. Are you sure you want to delete this item?",
                margin_bottom="20px",
            ),
            rx.hstack(
                rx.alert_dialog.action(
                    rx.button("Delete", color_scheme="red", on_click=ContextMenuDialogState.delete),
                ),
                rx.spacer(),
                rx.alert_dialog.cancel(rx.button("Cancel")),
            ),
        ),
        open=ContextMenuDialogState.which_dialog_open == "delete",
        on_open_change=ContextMenuDialogState.set_which_dialog_open(""),
    ),
    rx.dialog.root(
        rx.dialog.content(
            rx.dialog.title("Settings"),
            rx.dialog.description("Set your settings in this settings dialog.", margin_bottom="20px"),
            rx.dialog.close(
                rx.button("Close", on_click=ContextMenuDialogState.save_settings),
            ),
        ),
        open=ContextMenuDialogState.which_dialog_open == "settings",
        on_open_change=ContextMenuDialogState.set_which_dialog_open(""),
    ),
    align="center",
)

注文書を仕上げる

ファイルを1行ずつrx.foreachで描き、各行をコンテキストメニューで包みます。項目のon_selectにそのファイル名を渡すことで、1つのハンドラーがどの行でも動くようにします。

notes.txt

budget.xlsx

photo.png

class ContextMenuFileState(rx.State):
    files: list[str] = ["notes.txt", "budget.xlsx", "photo.png"]
    starred: list[str] = []

    @rx.event
    def toggle_star(self, name: str):
        if name in self.starred:
            self.starred = [f for f in self.starred if f != name]
        else:
            self.starred = self.starred + [name]

    @rx.event
    def duplicate(self, name: str):
        stem, dot, ext = name.rpartition(".")
        self.files = self.files + [f"{stem} copy{dot}{ext}"]

    @rx.event
    def remove(self, name: str):
        self.files = [f for f in self.files if f != name]
        self.starred = [f for f in self.starred if f != name]

    @rx.event
    def reset_files(self):
        self.files = ["notes.txt", "budget.xlsx", "photo.png"]
        self.starred = []


rx.vstack(
    rx.foreach(
        ContextMenuFileState.files,
        lambda name: rx.context_menu.root(
            rx.context_menu.trigger(
                rx.flex(
                    rx.icon("file"),
                    rx.text(name),
                    rx.spacer(),
                    rx.cond(ContextMenuFileState.starred.contains(name), rx.icon("star", color=rx.color("amber", 9))),
                    spacing="2",
                    align="center",
                    width="100%",
                    padding="6px 10px",
                    border_radius="6px",
                    _hover={"background": rx.color("gray", 3)},
                ),
            ),
            rx.context_menu.content(
                rx.context_menu.item("Star / unstar", on_select=ContextMenuFileState.toggle_star(name)),
                rx.context_menu.item("Duplicate", shortcut="⌘ D", on_select=ContextMenuFileState.duplicate(name)),
                rx.context_menu.separator(),
                rx.context_menu.item("Delete", shortcut="⌘ ⌫", color_scheme="red", on_select=ContextMenuFileState.remove(name)),
            ),
        ),
    ),
    rx.button("Reset", size="1", variant="soft", on_click=ContextMenuFileState.reset_files),
    width="100%",
    max_width="320px",
    spacing="1",
)

工房ノート

  • 右クリック(長押し)で開く。パーツはドロップダウンメニューと同じ:root · trigger · content · item · separator · sub。

  • itemはcontentの直接の子でなければならない。動的な項目はrx.foreachで直接描く。

  • rootにはopenがない。開閉を知りたいときはon_open_changeを使う。

  • triggerがdisabled=Trueならブラウザ標準のメニューが出る。

  • 右クリックは目に見えない機能。同じ操作をボタンやドロップダウンメニューでも用意する。

← 前へ

オーバーレイ · Dropdown Menu

次へ →

オーバーレイ · Toast

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

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

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

質問と回答

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

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

R

ReflexKR

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

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

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

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

Built with Reflex