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.dialog.rootrx.dialog.triggerrx.dialog.contentrx.dialog.titlerx.dialog.descriptionrx.dialog.closeDocumentación oficial
Pedido del taller
Al pulsar el botón «Editar perfil» de la tarjeta de socio, abre una ventana en el centro de la pantalla para corregir el nombre y el correo y guardarlos.
rx.dialog es una ventana modal que aparece en el centro de la pantalla. Mientras está abierta, el fondo se oscurece y no se puede pulsar, así que el usuario se concentra en lo que hay dentro. Sirve para tareas pequeñas que se terminan de una vez, como editar datos o añadir un elemento nuevo. Se construye con seis partes.
dialog.root: envuelve todas las partes del diálogo.dialog.trigger: envuelve el elemento que abre el diálogo al pulsarlo.dialog.content: el contenido de la ventana.dialog.title: el título de la ventana. Los lectores de pantalla lo leen al abrirse.dialog.description: la descripción de la ventana. Se lee junto con el título al abrirse.dialog.close: envuelve un elemento que cierra la ventana al pulsarlo.rx.dialog.root(
rx.dialog.trigger(rx.button("Open Dialog")),
rx.dialog.content(
rx.dialog.title("Welcome to Reflex!"),
rx.dialog.description(
"This is a dialog component. You can render anything you want in here.",
),
rx.dialog.close(
rx.button("Close Dialog", size="3"),
),
),
)El tamaño de la ventana lo deciden size (relleno interior) y max_width (ancho máximo) de dialog.content. Cambia un valor y abre la ventana.
Prueba las propiedades
title
description
size
max_width
rx.dialog.root(
rx.dialog.trigger(rx.button("Open dialog")),
rx.dialog.content(
rx.dialog.title("Invite teammates"),
rx.dialog.description("They will get an email with a link."),
rx.flex(
rx.dialog.close(rx.button("Close", variant="soft", color_scheme="gray")),
justify="end",
margin_top="16px",
),
size="3",
max_width="450px",
),
)| Parte | Propiedad | Valores | Uso |
|---|---|---|---|
root | open | True / False | Decidir la apertura desde el State (controlado). Junto con on_open_change |
root | default_open | True / False | Abierto en el primer renderizado (no controlado) |
root | on_open_change | Evento | Al abrirse o cerrarse. Pasa el nuevo valor de apertura (bool) |
content | size | "1" ~ "4" | Tamaño del relleno y de las esquinas |
content | on_open_auto_focus · on_close_auto_focus | Evento | Cuando el foco entra en la ventana al abrirse o vuelve al trigger al cerrarse |
content | on_escape_key_down | Evento | Al pulsar la tecla Esc |
content | on_pointer_down_outside · on_interact_outside | Evento | Al pulsar o interactuar fuera de la ventana |
trigger, title, description y close solo tienen los eventos comunes. También se cierra con la tecla Esc o pulsando fuera de la ventana.
Una ventana de edición de perfil con campos de texto y, debajo, los botones de cancelar y guardar uno junto al otro. Los dos están envueltos en dialog.close, así que al pulsarlos la ventana se cierra. Cómo guardar los valores de verdad se ve más abajo, en «Enviar un formulario», y en el pedido.
rx.dialog.root(
rx.dialog.trigger(rx.button("Edit Profile", size="4")),
rx.dialog.content(
rx.dialog.title("Edit Profile"),
rx.dialog.description(
"Change your profile details and preferences.",
size="2",
margin_bottom="16px",
),
rx.flex(
rx.text("Name", as_="div", size="2", margin_bottom="4px", weight="bold"),
rx.input(default_value="Freja Johnson", placeholder="Enter your name"),
rx.text("Email", as_="div", size="2", margin_bottom="4px", weight="bold"),
rx.input(default_value="freja@example.com", placeholder="Enter your email"),
direction="column",
spacing="3",
),
rx.flex(
rx.dialog.close(
rx.button("Cancel", color_scheme="gray", variant="soft"),
),
rx.dialog.close(
rx.button("Save"),
),
spacing="3",
margin_top="16px",
justify="end",
),
),
)Si lo envuelves en rx.inset(side="x"), un contenido como una tabla llega hasta los bordes laterales de la ventana.
rx.dialog.root(
rx.dialog.trigger(rx.button("View users", size="4")),
rx.dialog.content(
rx.dialog.title("Users"),
rx.dialog.description("The following users have access to this project."),
rx.inset(
rx.table.root(
rx.table.header(
rx.table.row(
rx.table.column_header_cell("Full Name"),
rx.table.column_header_cell("Email"),
rx.table.column_header_cell("Group"),
),
),
rx.table.body(
rx.table.row(
rx.table.row_header_cell("Danilo Rosa"),
rx.table.cell("danilo@example.com"),
rx.table.cell("Developer"),
),
rx.table.row(
rx.table.row_header_cell("Zahra Ambessa"),
rx.table.cell("zahra@example.com"),
rx.table.cell("Admin"),
),
),
),
side="x",
margin_top="24px",
margin_bottom="24px",
),
rx.flex(
rx.dialog.close(
rx.button("Close", variant="soft", color_scheme="gray"),
),
spacing="3",
justify="end",
),
),
)El on_open_change de dialog.root pasa True cuando se abre y False cuando se cierra. Sirve para contar aperturas o para limpiar los campos al cerrar la ventana.
Opened or closed: 0 times
Dialog open: no
class DialogEventState(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: ", DialogEventState.num_opens, " times"),
rx.text("Dialog open: ", rx.cond(DialogEventState.opened, "yes", "no")),
rx.dialog.root(
rx.dialog.trigger(rx.button("Open Dialog")),
rx.dialog.content(
rx.dialog.title("Welcome to Reflex!"),
rx.dialog.description(
"This is a dialog component. You can render anything you want in here.",
),
rx.dialog.close(
rx.button("Close Dialog", size="3"),
),
),
on_open_change=DialogEventState.count_opens,
),
direction="column",
spacing="3",
align="start",
)Si conectas un valor del State a open, el código puede abrir la ventana incluso sin dialog.trigger. Abajo, cada botón carga un valor distinto y abre la ventana. Si conectas también on_open_change, el State se mantiene al día aunque la ventana se cierre con Esc o pulsando fuera.
Cómo abrir un diálogo desde una opción de un menú desplegable se explica en la página Dropdown Menu.
class DialogControlState(rx.State):
open: bool = False
seconds: int = 0
@rx.event
def set_open(self, value: bool):
self.open = value
@rx.event
def start(self, seconds: int):
self.seconds = seconds
self.open = True
@rx.event
def confirm(self):
self.open = False
rx.flex(
rx.button("Break: 5 min", variant="soft", on_click=DialogControlState.start(5)),
rx.button("Break: 15 min", variant="soft", on_click=DialogControlState.start(15)),
rx.dialog.root(
rx.dialog.content(
rx.dialog.title("Take a break"),
rx.dialog.description("Stand up and stretch for ", DialogControlState.seconds, " minutes."),
rx.flex(rx.button("OK", on_click=DialogControlState.confirm), justify="end", margin_top="16px"),
max_width="380px",
),
open=DialogControlState.open,
on_open_change=DialogControlState.set_open,
),
spacing="3",
wrap="wrap",
)Con un rx.form dentro de la ventana recibes todos los valores de una vez. Si envuelves el botón de envío en dialog.close, la ventana se cierra al enviar. El handler recibe un dict cuyas claves son los name y muestra un aviso (toast).
class DialogFormState(rx.State):
current_user: dict[str, str] = {}
@rx.event
def add_user(self, form_data: dict):
self.current_user = form_data
# Here you would save the user to a database (see the Database course).
return rx.toast.info(
f"User {form_data.get('name', '')} has been added.", position="bottom-right"
)
rx.dialog.root(
rx.dialog.trigger(
rx.button(rx.icon("plus", size=26), rx.text("Add User", size="4")),
),
rx.dialog.content(
rx.dialog.title("Add New User"),
rx.dialog.description("Fill the form with the user's info"),
rx.form(
rx.flex(
rx.input(placeholder="User Name", name="name"),
rx.input(placeholder="user@reflex.dev", name="email"),
rx.flex(
rx.dialog.close(
rx.button("Cancel", variant="soft", color_scheme="gray"),
),
rx.dialog.close(
rx.button("Submit", type="submit"),
),
spacing="3",
justify="end",
),
direction="column",
spacing="4",
),
on_submit=DialogFormState.add_user,
reset_on_submit=False,
),
max_width="450px",
),
)El ejemplo de la documentación oficial guarda los datos en una base de datos en ese mismo punto. Esa parte, por separado, queda así (en esta página no se ejecuta).
from sqlmodel import select
class User(rx.Model, table=True):
name: str
email: str
@rx.event
def add_user_to_db(self, form_data: dict):
with rx.session() as session:
if session.exec(select(User).where(User.email == form_data["email"])).first():
return rx.window_alert("User with this email already exists")
session.add(User(**form_data))
session.commit()
return rx.toast.info(f"User {form_data['name']} has been added.")Esta vez la ventana se controla desde el State. El botón de guardar no va envuelto en dialog.close: el handler de envío guarda los valores y luego cierra la ventana con self.open = False. Así la ventana solo se cierra cuando el guardado ha terminado. Los campos se rellenan con los valores actuales mediante default_value.
Freja Johnson
freja@example.com
class DialogProfileState(rx.State):
open: bool = False
name: str = "Freja Johnson"
email: str = "freja@example.com"
@rx.event
def set_open(self, value: bool):
self.open = value
@rx.event
def save(self, form_data: dict):
self.name = form_data.get("name", "").strip() or self.name
self.email = form_data.get("email", "").strip() or self.email
self.open = False
return rx.toast.success("Profile saved")
rx.card(
rx.flex(
rx.avatar(fallback="FJ", radius="full"),
rx.box(
rx.text(DialogProfileState.name, weight="bold"),
rx.text(DialogProfileState.email, size="2", color_scheme="gray"),
),
rx.spacer(),
rx.dialog.root(
rx.dialog.trigger(rx.button(rx.icon("pencil"), "Edit profile", variant="soft", size="2")),
rx.dialog.content(
rx.dialog.title("Edit profile"),
rx.dialog.description("Change your name and email.", size="2", margin_bottom="12px"),
rx.form(
rx.flex(
rx.input(name="name", default_value=DialogProfileState.name, placeholder="Name"),
rx.input(name="email", default_value=DialogProfileState.email, placeholder="Email", type="email"),
rx.flex(
rx.dialog.close(rx.button("Cancel", variant="soft", color_scheme="gray", type="button")),
rx.button("Save", type="submit"),
spacing="3",
justify="end",
),
direction="column",
spacing="3",
),
on_submit=DialogProfileState.save,
),
max_width="420px",
),
open=DialogProfileState.open,
on_open_change=DialogProfileState.set_open,
),
spacing="3",
align="center",
),
max_width="460px",
)Notas del taller
root · trigger · content · title · description · close. Pon siempre title (lo leen los lectores de pantalla).
El tamaño, con size ("1"~"4") y max_width en content; el contenido que debe llegar al borde, con rx.inset.
on_open_change pasa el nuevo valor de apertura (bool). Si lo controlas con open, puedes abrirlo sin trigger.
Formularios con rx.form + on_submit. Para cerrar al enviar, envuélvelo en close o pon open a False en el handler.
Para ventanas que exigen una respuesta, como confirmar o cancelar, usa Alert Dialog.
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.