R

ReflexKR

Reflex-Dokumentation

Die Komponentenwerkstatt: Reflex' 100 Bibliotheksbausteine

·

Kursüberblick

Layout

·

Box

·

Flex

·

Stack

·

Grid

·

Container

·

Section

·

Center

·

Spacer

·

Separator

·

Card

·

Inset

·

Aspect Ratio

·

Fragment

Typografie

·

Text

·

Heading

·

Link

·

Code

·

Markdown

·

Blockquote

·

Quote

·

Strong

·

Em

·

Kbd

Formulare

·

Button

·

Input

·

Text Area

·

Checkbox

·

Switch

·

Radio Group

·

Select

·

Slider

·

Form

·

Upload

Datenanzeige

·

Badge

·

Avatar

·

Icon

·

Callout

·

List

·

Data List

·

Code Block

·

Progress

·

Spinner

·

Scroll Area

·

Moment

Auf- und Zuklappen

·

Tabs

·

Accordion

·

Segmented Control

Overlays

·

Tooltip

·

Popover

·

Hover Card

·

Dialog

·

Alert Dialog

·

Drawer

·

Dropdown Menu

·

Context Menu

·

Toast

Dynamisches Rendern

·

Cond

·

Match

·

Foreach

·

Auto Scroll

Medien

·

Image

·

Audio

·

Video

Tabellen und Datengrids

·

Table

·

Data Table

·

Data Editor

Diagramme

·

Area Chart

·

Bar Chart

·

Line Chart

·

Composed Chart

·

Pie Chart

·

Radar Chart

·

Radial Bar Chart

·

Scatter Chart

·

Funnel Chart

·

Treemap

·

Sankey Chart

·

Error Bar

Diagrammbausteine

·

Axis

·

Cartesian Grid

·

Chart Tooltip

·

Legend

·

Label

·

Reference

·

Brush

Andere Diagrammbibliotheken

·

Plotly

·

Pyplot

HTML-Elemente

·

HTML

·

HTML Text

·

HTML Layout

·

HTML Forms

·

HTML Media

·

HTML Tables

·

SVG

Weitere Werkzeuge

·

Theme

·

Skeleton

·

Clipboard

·

Html Embed

·

Script

·

Memo

Die Komponentenwerkstatt: Reflex' 100 Bibliotheksbausteine
Overlays

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

Offizielle Doku

Werkstattauftrag

Klickt man in der Dateiliste mit der rechten Maustaste auf einen Dateinamen, soll genau dort ein Menü erscheinen, in dem man Markieren, Duplizieren oder Löschen wählt.

Ein Kontextmenü erscheint an der Mausposition, wenn man ein Element mit der rechten Maustaste anklickt (auf Touchscreens: lange gedrückt hält). Man sammelt darin, was man „mit diesem Ding“ tun kann, etwa mit einer Datei, einer Tabellenzeile oder einem Bild. Die Teile sind dieselben wie beim Dropdown-Menü.

  • context_menu.root: umschließt alle Teile.
  • context_menu.trigger: umschließt das Element, das den Rechtsklick empfängt.
  • context_menu.content: das Panel, das im geöffneten Zustand erscheint.
  • context_menu.item: ein einzelner Eintrag. Mit shortcut bekommt er ein Tastenkürzel.
  • context_menu.separator: eine Linie zwischen Einträgen.
  • context_menu.sub: umschließt ein Untermenü. Darin stehen context_menu.sub_trigger und 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"),
    ),
)

Props ausprobieren

Klicke mit der rechten Maustaste in den gestrichelten Kasten. Das Aussehen des Menüpanels gehört an content, disabled zum Sperren des Rechtsklicks an trigger. Ist disabled an, erscheint das normale Kontextmenü des Browsers.

Props ausprobieren

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,
)
Ein Kontextmenü öffnet sich dort, wo man klickt. Statt side und align ändert man daher meist variant, size und color_scheme.
TeilPropWerteVerwendung
rootmodalTrue / FalseBedienung außerhalb sperren, solange es offen ist
rooton_open_changeEventBeim Öffnen oder Schließen; übergibt den neuen Offen-Wert (bool)
triggerdisabledTrue / FalseÖffnen per Rechtsklick verhindern
contentvariant · size"solid" "soft" · "1" "2"Hervorhebungsstil, Größe
contentcolor_scheme · high_contrastFarbname · boolFarbe der Einträge, Kontrast
contentloop · side · align · side_offset · align_offset-Tastatur-Schleife, Feinjustierung der Position
contentavoid_collisions · collision_padding · sticky · hide_when_detached-Verhalten am Bildschirmrand
itemshortcut · color_scheme · disabled · text_value-Tastenkürzel, Farbe, nicht auswählbar, Text für die Tipp-Suche
itemon_selectEventWenn ein Eintrag gewählt wird
subopen · default_open · on_open_change-Offen-Zustand des Untermenüs
sub_triggerdisabled · text_value-Eintrag, der das Untermenü öffnet
sub_contentloop · side_offset · align_offset usw.-Position des Unterpanels

Anders als beim Dropdown-Menü hat root kein open: Das Menü öffnet sich nur per Rechtsklick. content und sub_content haben die Events on_escape_key_down, on_pointer_down_outside, on_focus_outside und on_interact_outside.

Einträge direkt unter content

context_menu.item muss ein direktes Kind von context_menu.content sein. Fasst du Einträge in einen Container wie rx.vstack, um sie je nach Bedingung auszutauschen, erkennt das Menü sie nicht mehr. Diese Form verbietet die offizielle Doku:

rx.context_menu.content(
    rx.cond(
        State.count % 2 == 0,
        rx.vstack(  # nicht in einen Container packen
            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"),
        ),
    )
)

Sollen die Einträge vom State abhängen, machst du die Liste zu einer berechneten Variable und zeichnest die Einträge direkt mit rx.foreach. rx.foreach erzeugt keinen eigenen Container. Klicke unten auf den count-Button und dann erneut mit der rechten Maustaste.

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",
)

Beim Öffnen und Schließen: on_open_change

on_open_change an context_menu.root übergibt beim Öffnen True und beim Schließen 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",
)

Einen Dialog aus dem Menü öffnen

Wie beim Dropdown-Menü verschwindet ein Dialog, der in einem Menüeintrag steckt, sobald sich das Menü schließt. Lege den Dialog deshalb außerhalb des Menüs ab; der Eintrag ändert nur einen State-Wert. Jeder Dialog öffnet sich, wenn dieser Wert seinem Namen entspricht, und beim Schließen leert on_open_change den Wert. Klicke unten mit der rechten Maustaste auf das Icon.

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",
)

Auftrag erledigt

Jede Dateizeile wird mit rx.foreach gezeichnet und in ein eigenes Kontextmenü gehüllt. Das on_select der Einträge erhält den jeweiligen Dateinamen, sodass ein einziger Handler für jede Zeile funktioniert.

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",
)

Werkstattnotizen

  • Öffnet per Rechtsklick (langes Drücken). Die Teile sind wie beim Dropdown-Menü: root · trigger · content · item · separator · sub.

  • item muss ein direktes Kind von content sein. Dynamische Einträge direkt mit rx.foreach zeichnen.

  • root hat kein open. Wer wissen will, ob es offen ist, nutzt on_open_change.

  • Mit disabled=True am trigger erscheint das normale Kontextmenü des Browsers.

  • Ein Rechtsklick ist eine unsichtbare Funktion. Dieselben Aktionen auch per Button oder Dropdown-Menü anbieten.

← Zurück

Overlays · Dropdown Menu

Weiter →

Overlays · Toast

Über neue Lektionen informiert werden

Wir schicken dir eine E-Mail, wenn dieser Kurs neue Lektionen bekommt oder ein Folgekurs erscheint.

Erhoben: deine E-Mail-Adresse · Zweck: Hinweise auf neue Lektionen oder den Start dieses Kurses · Speicherdauer: bis du die Löschung verlangst. Keine andere Nutzung, keine Weitergabe. Antworte einfach auf eine Benachrichtigung, dann löschen wir sie sofort.

Fragen & Antworten

Frag alles zu dieser Lektion. Fragen aus allen Sprachversionen dieser Seite erscheinen hier gemeinsam.

Wird als reiner Text angezeigt, ohne Links oder Formatierung.

R

ReflexKR

Python und Reflex zum Anfassen. Alle Beispiele wurden mit Reflex 0.10.0 ausgeführt und geprüft.

ReflexKR ist kostenlos und ohne Werbebanner. Wenn es dir geholfen hat, kannst du es mit einem Kaffee unterstützen. ☕ Spendier uns einen Kaffee

Hinweis zu Affiliate-Links
한국어English日本語简体中文EspañolDeutsch

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

Built with Reflex