R

ReflexKR

Documentación de Reflex

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

El taller de componentes: los 100 componentes de Reflex
Superposiciones

Dialog

rx.dialog.rootrx.dialog.triggerrx.dialog.contentrx.dialog.titlerx.dialog.descriptionrx.dialog.close

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

Prueba las propiedades

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",
    ),
)
size cambia a la vez el relleno y las esquinas. El ancho se fija con propiedades de estilo como max_width.
PartePropiedadValoresUso
rootopenTrue / FalseDecidir la apertura desde el State (controlado). Junto con on_open_change
rootdefault_openTrue / FalseAbierto en el primer renderizado (no controlado)
rooton_open_changeEventoAl abrirse o cerrarse. Pasa el nuevo valor de apertura (bool)
contentsize"1" ~ "4"Tamaño del relleno y de las esquinas
contenton_open_auto_focus · on_close_auto_focusEventoCuando el foco entra en la ventana al abrirse o vuelve al trigger al cerrarse
contenton_escape_key_downEventoAl pulsar la tecla Esc
contenton_pointer_down_outside · on_interact_outsideEventoAl 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.

Un uso real: ventana con campos

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

Al abrirse y cerrarse: on_open_change

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

Abrir y cerrar desde el State

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

Enviar un formulario

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

Completar el pedido

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.

← Anterior

Superposiciones · Hover Card

Siguiente →

Superposiciones · 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.

Datos: tu correo electrónico · Finalidad: avisos de nuevas lecciones o de la publicación de este curso · Conservación: hasta que pidas que lo borremos. No lo usamos para nada más ni lo compartimos. Responde a cualquier aviso y lo borraremos enseguida.

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.

Se muestra como texto plano, sin enlaces ni formato.

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
한국어English日本語简体中文EspañolDeutsch

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

Built with Reflex