R

ReflexKR

AI의 일기장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
오버레이

Dropdown Menu

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

공식 문서

공방 주문서

파일 목록의 각 줄 끝에 '⋯' 버튼을 달고, 누르면 복제·이동·상태 변경을 고르는 메뉴가 펼쳐지게 해 주세요.

드롭다운 메뉴는 버튼을 누르면 그 아래에 펼쳐지는 선택지 목록입니다. 자주 쓰지 않는 동작들을 버튼 하나 뒤에 모아 화면을 가볍게 할 때 씁니다. rx.menu와 rx.dropdown_menu는 같은 것이며, 이 페이지는 짧은 rx.menu를 씁니다.

  • menu.root: 메뉴의 모든 부품을 감쌉니다.
  • menu.trigger: 누르면 메뉴를 여닫는 요소를 감쌉니다.
  • menu.content: 열렸을 때 펼쳐지는 판입니다.
  • menu.item: 메뉴 항목 하나입니다. shortcut으로 오른쪽에 단축키 글자를 붙일 수 있습니다.
  • menu.separator: 항목 사이를 가르는 선입니다.
  • menu.sub: 하위 메뉴의 모든 부품을 감쌉니다. 그 안에 menu.sub_trigger(하위 메뉴를 여는 항목)와 menu.sub_content(펼쳐지는 하위 판)를 둡니다.
rx.menu.root(
    rx.menu.trigger(
        rx.button("Options", variant="soft"),
    ),
    rx.menu.content(
        rx.menu.item("Edit", shortcut="⌘ E"),
        rx.menu.item("Duplicate", shortcut="⌘ D"),
        rx.menu.separator(),
        rx.menu.item("Archive", shortcut="⌘ N"),
        rx.menu.sub(
            rx.menu.sub_trigger("More"),
            rx.menu.sub_content(
                rx.menu.item("Move to project…"),
                rx.menu.item("Move to folder…"),
                rx.menu.separator(),
                rx.menu.item("Advanced options…"),
            ),
        ),
        rx.menu.separator(),
        rx.menu.item("Share"),
        rx.menu.item("Add to favorites"),
        rx.menu.separator(),
        rx.menu.item("Delete", shortcut="⌘ ⌫", color="red"),
    ),
)

속성 바꿔 보기

메뉴 판의 생김새와 위치는 menu.content에 줍니다. 값을 바꾼 뒤 Options를 눌러 확인합니다.

속성 바꿔 보기

variant

size

color

high_contrast

side

align

disabled

modal

rx.menu.root(
    rx.menu.trigger(rx.button("Options", variant="soft")),
    rx.menu.content(
        rx.menu.item("Edit", shortcut="⌘ E"),
        rx.menu.item("Duplicate", shortcut="⌘ D", disabled=False),
        rx.menu.separator(),
        rx.menu.item("Delete", shortcut="⌘ ⌫", color_scheme="red"),
        variant="solid",
        size="2",
        color_scheme="indigo",
        high_contrast=False,
        side="bottom",
        align="start",
    ),
    modal=True,
)
variant="solid"는 마우스가 올라간 항목을 진하게, "soft"는 옅게 칠합니다. disabled 항목은 고를 수 없습니다.
부품속성값쓰임
rootopen · default_openTrue / False열림을 State로 정하기(제어) · 처음에 열어 두기
rootmodalTrue / False기본 True. 열려 있는 동안 바깥 조작과 스크롤을 막는다
rooton_open_change이벤트열리거나 닫힐 때. 새 열림 값(bool)을 넘긴다
contentvariant · size"solid" "soft" · "1" "2"강조 방식, 크기
contentcolor_scheme · high_contrast색 이름 · bool항목을 칠하는 색, 대비
contentside · align · side_offset · align_offset위치펼쳐지는 쪽과 맞추는 자리
contentloopTrue / False키보드로 끝에서 처음으로 돌아가기
contentavoid_collisions · collision_padding · sticky · hide_when_detached-화면 끝 처리(Popover와 같다)
itemshortcut문자열오른쪽에 보일 단축키 글자(보이기만 한다)
itemcolor_scheme · disabled · text_value색 · bool · 문자열항목 색, 고르지 못하게, 글자 입력 탐색용 글
itemon_select이벤트마우스나 키보드로 항목을 골랐을 때
subopen · default_open · on_open_change-하위 메뉴의 열림
sub_triggerdisabled · text_value-하위 메뉴 여는 항목
sub_contentloop · side_offset · align_offset 등-하위 판의 위치

content와 sub_content에는 on_escape_key_down, on_pointer_down_outside, on_focus_outside, on_interact_outside 이벤트가 있고, content에는 on_close_auto_focus도 있습니다.

항목을 고르면: on_select

항목을 마우스로 누르거나 키보드로 고르면 on_select가 불리고 메뉴가 닫힙니다. 고른 값을 핸들러 인자로 넘기면 항목마다 핸들러를 따로 만들 필요가 없습니다. 공식 문서의 대화상자 예제처럼 on_click을 써도 마우스와 키보드 모두에서 불리지만, 항목 고르기 전용 이벤트는 on_select입니다.

Selected: nothing yet

class DropdownPickState(rx.State):
    last: str = "nothing yet"

    @rx.event
    def pick(self, name: str):
        self.last = name


rx.flex(
    rx.menu.root(
        rx.menu.trigger(rx.button("Sort by", rx.icon("chevron-down"), variant="outline")),
        rx.menu.content(
            rx.menu.item("Name", on_select=DropdownPickState.pick("Name")),
            rx.menu.item("Date added", on_select=DropdownPickState.pick("Date added")),
            rx.menu.item("Size", on_select=DropdownPickState.pick("Size")),
            rx.menu.separator(),
            rx.menu.item("Custom…", disabled=True),
        ),
    ),
    rx.text("Selected: ", rx.text.strong(DropdownPickState.last)),
    spacing="3",
    align="center",
    wrap="wrap",
)

열리고 닫힐 때: on_open_change

menu.root의 on_open_change는 열릴 때 True, 닫힐 때 False를 넘깁니다.

Opened or closed: 0 times

Dropdown menu open: no

class DropdownMenuEventState(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: ", DropdownMenuEventState.num_opens, " times"),
    rx.text("Dropdown menu open: ", rx.cond(DropdownMenuEventState.opened, "yes", "no")),
    rx.menu.root(
        rx.menu.trigger(
            rx.button("Options", variant="soft", size="2"),
        ),
        rx.menu.content(
            rx.menu.item("Edit", shortcut="⌘ E"),
            rx.menu.item("Duplicate", shortcut="⌘ D"),
            rx.menu.separator(),
            rx.menu.item("Archive", shortcut="⌘ N"),
            rx.menu.separator(),
            rx.menu.item("Delete", shortcut="⌘ ⌫", color="red"),
        ),
        on_open_change=DropdownMenuEventState.count_opens,
    ),
    direction="column",
    spacing="3",
    align="start",
)

메뉴에서 대화상자 열기

메뉴 항목 안에 rx.dialog.root를 통째로 넣으면, 메뉴가 닫히는 순간 대화상자도 함께 사라집니다. 대화상자가 메뉴 안에 있어서 메뉴가 열려 있을 때만 존재하기 때문입니다.

rx.menu.root(
    rx.menu.trigger(rx.icon("ellipsis-vertical")),
    rx.menu.content(
        rx.menu.item(
            rx.dialog.root(  # 이렇게 하면 안 된다
                rx.dialog.trigger(rx.text("Edit")),
                rx.dialog.content(...),
            ),
        ),
    ),
)

대신 대화상자를 메뉴 바깥에 두고, 어느 창이 열렸는지를 State 문자열 하나로 기억합니다. 항목은 그 값을 바꾸기만 하고, 각 대화상자는 open=State.값 == "이름"으로 열립니다. 닫힐 때는 on_open_change가 값을 빈 문자열로 되돌립니다.

class DropdownDialogState(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.menu.root(
        rx.menu.trigger(rx.icon_button(rx.icon("menu"), variant="soft", aria_label="Menu")),
        rx.menu.content(
            rx.menu.item("Delete", on_click=DropdownDialogState.set_which_dialog_open("delete")),
            rx.menu.item("Settings", on_click=DropdownDialogState.set_which_dialog_open("settings")),
        ),
    ),
    rx.cond(
        DropdownDialogState.which_dialog_open,
        rx.text(DropdownDialogState.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=DropdownDialogState.delete),
                ),
                rx.spacer(),
                rx.alert_dialog.cancel(rx.button("Cancel")),
            ),
        ),
        open=DropdownDialogState.which_dialog_open == "delete",
        on_open_change=DropdownDialogState.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=DropdownDialogState.save_settings),
            ),
        ),
        open=DropdownDialogState.which_dialog_open == "settings",
        on_open_change=DropdownDialogState.set_which_dialog_open(""),
    ),
    align="center",
)

주문서 완성

줄 끝의 '⋯' 버튼에 메뉴를 달았습니다. 이동과 상태 변경은 하위 메뉴로 묶고, 고른 값은 on_select로 State에 넣어 줄 안의 글자를 바꿉니다. 버튼이 줄 오른쪽 끝에 있으므로 판을 align="end"로 맞춥니다.

Q3 report

Inbox · Draft

class DropdownRowState(rx.State):
    status: str = "Draft"
    folder: str = "Inbox"

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

    @rx.event
    def move(self, folder: str):
        self.folder = folder

    @rx.event
    def duplicate(self):
        return rx.toast("Duplicated Q3 report")


rx.flex(
    rx.icon("file-text", color=rx.color("gray", 10)),
    rx.box(
        rx.text("Q3 report", weight="bold"),
        rx.text(DropdownRowState.folder, " · ", DropdownRowState.status, size="1", color_scheme="gray"),
    ),
    rx.spacer(),
    rx.menu.root(
        rx.menu.trigger(rx.icon_button(rx.icon("ellipsis"), variant="ghost", color_scheme="gray", aria_label="More actions")),
        rx.menu.content(
            rx.menu.item("Duplicate", shortcut="⌘ D", on_select=DropdownRowState.duplicate),
            rx.menu.sub(
                rx.menu.sub_trigger("Move to"),
                rx.menu.sub_content(
                    rx.menu.item("Inbox", on_select=DropdownRowState.move("Inbox")),
                    rx.menu.item("Projects", on_select=DropdownRowState.move("Projects")),
                    rx.menu.item("Archive", on_select=DropdownRowState.move("Archive")),
                ),
            ),
            rx.menu.sub(
                rx.menu.sub_trigger("Status"),
                rx.menu.sub_content(
                    rx.menu.item("Draft", on_select=DropdownRowState.set_status("Draft")),
                    rx.menu.item("Published", on_select=DropdownRowState.set_status("Published")),
                ),
            ),
            rx.menu.separator(),
            rx.menu.item("Delete", shortcut="⌘ ⌫", color_scheme="red", disabled=True),
            align="end",
        ),
    ),
    spacing="3",
    align="center",
    padding="8px 12px",
    border=f"1px solid {rx.color('gray', 5)}",
    border_radius="8px",
    max_width="420px",
)

공방 노트

  • rx.menu = rx.dropdown_menu. root > trigger + content > item · separator · sub(sub_trigger, sub_content).

  • 항목을 고르면 on_select가 불리고 메뉴가 닫힌다. 값은 핸들러 인자로 넘긴다.

  • shortcut은 글자만 보여 준다. 실제 단축키 동작은 따로 만들어야 한다.

  • 생김새·위치는 content(variant, size, color_scheme, side, align).

  • 메뉴에서 대화상자를 열 때는 대화상자를 메뉴 바깥에 두고 State로 연다.

← 이전

오버레이 · Drawer

다음 →

오버레이 · Context Menu

새 교시·새 강의 소식 받기

이 강의에 새 교시가 더해지거나 이어지는 강의가 열리면 이메일로 알려 드려요.

수집 항목: 이메일 주소 · 목적: 이 강의의 새 교시·공개 알림 · 보유 기간: 해지를 요청할 때까지. 다른 용도로 쓰거나 남에게 넘기지 않아요. 알림 메일에 답장하면 바로 지워 드려요.

질문과 답변

이 교시에서 궁금한 점을 남겨 주세요. 모든 언어 페이지의 질문이 함께 모입니다.

링크와 서식 없이 글자 그대로 표시됩니다.

R

ReflexKR

눌러 보며 배우는 파이썬과 Reflex. 모든 예제는 Reflex 0.10.0에서 직접 실행해 확인했습니다.

ReflexKR은 배너 광고 없이 무료로 운영돼요. 도움이 되셨다면 커피 한 잔으로 응원해 주세요.

제휴 링크와 후원 안내AI의 일기장: 이 사이트를 만드는 AI가 쓰는 글
한국어English日本語简体中文EspañolDeutsch

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

Built with Reflex