El taller de componentes: los 100 componentes de Reflex
·
Resumen del curso
Diseño
·
Box
·
Flex
·
Stack
·
Grid
·
Container
·
Section
·
Center
·
Spacer
·
Separator
·
Card
·
Inset
·
Aspect Ratio
·
Fragment
Tipografía
·
Text
·
Heading
·
Link
·
Code
·
Markdown
·
Blockquote
·
Quote
·
Strong
·
Em
·
Kbd
Formularios
·
Button
·
Input
·
Text Area
·
Checkbox
·
Switch
·
Radio Group
·
Select
·
Slider
·
Form
·
Upload
Visualización de datos
·
Badge
·
Avatar
·
Icon
·
Callout
·
List
·
Data List
·
Code Block
·
Progress
·
Spinner
·
Scroll Area
·
Moment
Mostrar y ocultar
·
Tabs
·
Accordion
·
Segmented Control
Superposiciones
·
Tooltip
·
Popover
·
Hover Card
·
Dialog
·
Alert Dialog
·
Drawer
·
Dropdown Menu
·
Context Menu
·
Toast
Renderizado dinámico
·
Cond
·
Match
·
Foreach
·
Auto Scroll
Multimedia
·
Image
·
Audio
·
Video
Tablas y cuadrículas de datos
·
Table
·
Data Table
·
Data Editor
Gráficos
·
Area Chart
·
Bar Chart
·
Line Chart
·
Composed Chart
·
Pie Chart
·
Radar Chart
·
Radial Bar Chart
·
Scatter Chart
·
Funnel Chart
·
Treemap
·
Sankey Chart
·
Error Bar
Piezas de gráficos
·
Axis
·
Cartesian Grid
·
Chart Tooltip
·
Legend
·
Label
·
Reference
·
Brush
Otras bibliotecas de gráficos
·
Plotly
·
Pyplot
Elementos HTML
·
HTML
·
HTML Text
·
HTML Layout
·
HTML Forms
·
HTML Media
·
HTML Tables
·
SVG
Otras herramientas
·
Theme
·
Skeleton
·
Clipboard
·
Html Embed
·
Script
·
Memo
rx.menu.rootrx.menu.triggerrx.menu.contentrx.menu.itemrx.menu.separatorrx.menu.subrx.menu.sub_triggerrx.menu.sub_contentDocumentación oficial
Pedido del taller
Pon un botón «⋯» al final de cada fila de la lista de archivos que, al pulsarlo, despliegue un menú para duplicar, mover o cambiar el estado.
Un menú desplegable es una lista de opciones que se despliega bajo un botón al pulsarlo. Sirve para aligerar la pantalla reuniendo detrás de un solo botón las acciones que se usan poco. rx.menu y rx.dropdown_menu son lo mismo; esta página usa la forma corta, rx.menu.
menu.root: envuelve todas las partes del menú.menu.trigger: envuelve el elemento que abre y cierra el menú al pulsarlo.menu.content: el panel que se despliega al abrirse.menu.item: una opción del menú. Con shortcut puedes añadir a la derecha el texto de un atajo de teclado.menu.separator: una línea que separa opciones.menu.sub: envuelve todas las partes de un submenú. Dentro van menu.sub_trigger (la opción que abre el submenú) y menu.sub_content (el panel secundario que se despliega).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"),
),
)El aspecto y la posición del panel van en menu.content. Cambia un valor y pulsa Options para comprobarlo.
Prueba las propiedades
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,
)| Parte | Propiedad | Valores | Uso |
|---|---|---|---|
root | open · default_open | True / False | Decidir la apertura desde el State (controlado) · abierto al principio |
root | modal | True / False | True por defecto. Bloquea la interacción exterior y el scroll mientras está abierto |
root | on_open_change | Evento | Al abrirse o cerrarse. Pasa el nuevo valor de apertura (bool) |
content | variant · size | "solid" "soft" · "1" "2" | Tipo de resaltado, tamaño |
content | color_scheme · high_contrast | Nombre de color · bool | Color con que se pintan las opciones, contraste |
content | side · align · side_offset · align_offset | Posición | Lado hacia el que se despliega y alineación |
content | loop | True / False | Volver del final al principio con el teclado |
content | avoid_collisions · collision_padding · sticky · hide_when_detached | - | Comportamiento en el borde de la pantalla (igual que Popover) |
item | shortcut | Cadena | Texto de atajo que se ve a la derecha (solo se muestra) |
item | color_scheme · disabled · text_value | Color · bool · cadena | Color de la opción, impedir elegirla, texto para buscar tecleando |
item | on_select | Evento | Al elegir la opción con el ratón o el teclado |
sub | open · default_open · on_open_change | - | Apertura del submenú |
sub_trigger | disabled · text_value | - | La opción que abre el submenú |
sub_content | loop · side_offset · align_offset, etc. | - | Posición del panel secundario |
content y sub_content tienen los eventos on_escape_key_down, on_pointer_down_outside, on_focus_outside y on_interact_outside, y content además tiene on_close_auto_focus.
Cuando se pulsa una opción con el ratón o se elige con el teclado, se llama a on_select y el menú se cierra. Si pasas el valor elegido como argumento del handler, no hace falta un handler distinto para cada opción. Como en el ejemplo del diálogo de la documentación oficial, on_click también se dispara con ratón y teclado, pero el evento pensado para elegir opciones es 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",
)El on_open_change de menu.root pasa True cuando se abre y False cuando se cierra.
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",
)Si metes un rx.dialog.root entero dentro de una opción del menú, el diálogo desaparece en cuanto el menú se cierra. Como el diálogo está dentro del menú, solo existe mientras el menú está abierto.
rx.menu.root(
rx.menu.trigger(rx.icon("ellipsis-vertical")),
rx.menu.content(
rx.menu.item(
rx.dialog.root( # así no funciona
rx.dialog.trigger(rx.text("Edit")),
rx.dialog.content(...),
),
),
),
)En su lugar, pon los diálogos fuera del menú y recuerda qué ventana está abierta con una sola cadena en el State. Las opciones solo cambian ese valor, y cada diálogo se abre con open=State.valor == "nombre". Al cerrarse, on_open_change devuelve el valor a la cadena vacía.
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",
)El menú va en el botón «⋯» al final de la fila. Mover y cambiar el estado se agrupan en submenús, y el valor elegido entra en el State con on_select para cambiar el texto de la fila. Como el botón está en el extremo derecho de la fila, el panel se alinea con 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",
)Notas del taller
rx.menu = rx.dropdown_menu. root > trigger + content > item · separator · sub(sub_trigger, sub_content).
Al elegir una opción se llama a on_select y el menú se cierra. El valor se pasa como argumento del handler.
shortcut solo muestra el texto. El atajo de teclado real hay que programarlo aparte.
Aspecto y posición en content (variant, size, color_scheme, side, align).
Para abrir un diálogo desde el menú, pon el diálogo fuera del menú y ábrelo desde el State.
Recibe avisos de nuevas lecciones
Te avisaremos por correo cuando este curso tenga lecciones nuevas o se abra un curso de continuación.
R
ReflexKR
Aprende Python y Reflex haciendo. Todos los ejemplos se ejecutaron y verificaron en Reflex 0.10.0.
ReflexKR es gratis y sin banners publicitarios. Si te ayudó, puedes apoyarlo con un café. ☕ Invítanos un café
Aviso de afiliados© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
Preguntas y respuestas
Pregunta lo que quieras sobre esta lección. Aquí se reúnen las preguntas de todas las versiones de idioma de esta página.