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.el.fieldsetrx.el.formrx.el.labelrx.el.legendrx.el.meterrx.el.optgrouprx.el.optionrx.el.outputrx.el.progressrx.el.selectrx.el.textareaDocumentación oficial
Pedido del taller
Formulario de pedidos de una cafetería: la bebida se elige de una lista agrupada por tipos, la forma de recogida con botones de radio y las peticiones en un texto de varias líneas; al pedir, muestra un resumen.
Son los elementos HTML relacionados con formularios: form, que reúne las entradas; la caja de agrupación fieldset y su título legend; la selección con select·optgroup·option; la entrada de varias líneas textarea, y meter·progress·output, que muestran valores.
Son más ligeros que los componentes de formulario de Radix (rx.select, rx.text_area) y usan tal cual el comportamiento que ofrece el navegador.
rx.el.label(
"Size ",
rx.el.select(
rx.el.option("Small", value="s"),
rx.el.option("Medium", value="m"),
rx.el.option("Large", value="l"),
default_value="m",
border="1px solid gray",
padding="2px 6px",
),
)meter cambia de color según el valor esté en una zona buena o mala. low·high son los límites de las zonas, y optimum decide cuál es la buena.
Prueba las propiedades
value
65
low
30
high
80
optimum
90
rx.el.div(
rx.el.meter(value=65, min=0, max=100, low=30, high=80, optimum=90, width="260px", height="20px"),
rx.el.progress(value=65, max=100, width="260px"),
display="flex",
flex_direction="column",
gap="10px",
)Prueba las propiedades
placeholder
rows
resize
disabled
read_only
rx.el.textarea(
placeholder="Write a note",
rows="4",
resize="vertical",
disabled=False,
read_only=False,
border="1px solid gray",
border_radius="6px",
padding="6px 8px",
width="280px",
)| Propiedad | Valores | Por defecto | Uso |
|---|---|---|---|
on_submit (form) | Event handler | Ninguno (solo impide el envío) | Recibe un dict con los valores por name |
reset_on_submit (form) | True / False | False | Vacía las casillas tras el envío |
no_validate (form) | True / False | False | Desactiva la comprobación de required·pattern del navegador |
html_for (label, output) | id del elemento | Ninguno | Casilla asociada. Al pulsar la etiqueta se va a esa casilla |
disabled (fieldset, select, option, optgroup) | True / False | False | Desactiva todas las entradas de dentro |
value / on_change (select, textarea) | Cadena / evento | Ninguno | Entrada controlada. default_value es no controlada |
multiple size (select) | bool / entero | False / ninguno | Elegir varios, número de líneas visibles |
label (optgroup) | Cadena | Ninguno | Título del grupo |
rows cols max_length (textarea) | Entero | Ninguno | Tamaño y límite de caracteres |
auto_height enter_key_submit (textarea) | True / False | False | Altura según el texto, enviar con Enter |
value min max low high optimum (meter) | Número | min=0 max=1 | Medida dentro de un rango |
value max (progress) | Número | max=1 | Grado de avance. Sin value, indica "en curso" |
Al pulsar el botón de envío, on_submit pasa los valores de las casillas del formulario como un dict cuyas claves son los name. Un checkbox solo entra, como "on", si está marcado.
Aunque no haya on_submit, rx.el.form impide el envío por defecto del navegador (recargar la página). Con reset_on_submit=True, las casillas se vacían tras el envío.
class HtmlFormSignupState(rx.State):
submitted: dict[str, str] = {}
@rx.event
def handle_submit(self, form_data: dict):
self.submitted = {key: str(value) for key, value in form_data.items()}
rx.el.div(
rx.el.form(
rx.el.input(name="email", type="email", placeholder="Email", required=True, border="1px solid gray", padding="4px 8px"),
rx.el.select(
rx.el.option("Weekly", value="weekly"),
rx.el.option("Monthly", value="monthly"),
name="plan",
border="1px solid gray",
padding="4px",
),
rx.el.label(rx.el.input(type="checkbox", name="news"), " Send news"),
rx.el.button("Sign up", type="submit", padding="4px 12px", border="1px solid gray", border_radius="6px"),
on_submit=HtmlFormSignupState.handle_submit,
reset_on_submit=True,
display="flex",
gap="8px",
flex_wrap="wrap",
align_items="center",
),
rx.el.ul(
rx.foreach(HtmlFormSignupState.submitted, lambda kv: rx.el.li(rx.el.code(kv[0]), " = ", kv[1])),
margin_top="10px",
),
)fieldset agrupa entradas relacionadas con un borde, y legend es el título del grupo. Si das disabled=True a fieldset, se desactivan todas las entradas de dentro.
label se asocia a una casilla envolviéndola o escribiendo el id de la casilla en html_for. Al pulsar una etiqueta asociada, el cursor va a la casilla.
rx.el.div(
rx.el.fieldset(
rx.el.legend("Delivery", font_weight="bold"),
rx.el.label(rx.el.input(type="radio", name="ship", value="pickup", default_checked=True), " Pickup"),
rx.el.label(rx.el.input(type="radio", name="ship", value="courier"), " Courier"),
border="1px solid gray",
border_radius="6px",
padding="8px 12px",
display="flex",
gap="12px",
),
rx.el.fieldset(
rx.el.legend("Gift wrap (sold out)", font_weight="bold"),
rx.el.label(rx.el.input(type="checkbox"), " Wrap it"),
rx.el.label("Message ", rx.el.input(id="htmlforms_gift_msg", border="1px solid gray")),
disabled=True,
border="1px solid gray",
border_radius="6px",
padding="8px 12px",
display="flex",
gap="12px",
opacity="0.6",
),
rx.el.label("Coupon", html_for="htmlforms_coupon", margin_right="8px"),
rx.el.input(id="htmlforms_coupon", placeholder="Click the label", border="1px solid gray", padding="2px 6px"),
display="flex",
flex_direction="column",
gap="10px",
align_items="start",
)option es un elemento a elegir y optgroup agrupa elementos bajo el título label. Los elementos disabled no se pueden elegir.
Con value y on_change, el State guarda el valor elegido. Con multiple=True y size, se eligen varios en una lista desplegada usando Ctrl·Shift.
You picked: soup
class HtmlFormSelectState(rx.State):
dish: str = "soup"
@rx.event
def change_dish(self, value: str):
self.dish = value
rx.el.div(
rx.el.select(
rx.el.optgroup(
rx.el.option("Soup", value="soup"),
rx.el.option("Salad", value="salad"),
label="Starters",
),
rx.el.optgroup(
rx.el.option("Pasta", value="pasta"),
rx.el.option("Steak (sold out)", value="steak", disabled=True),
label="Mains",
),
value=HtmlFormSelectState.dish,
on_change=HtmlFormSelectState.change_dish,
border="1px solid gray",
padding="4px",
),
rx.el.p("You picked: ", rx.el.strong(HtmlFormSelectState.dish)),
rx.el.select(
rx.el.option("Red"),
rx.el.option("Green"),
rx.el.option("Blue"),
rx.el.option("Black"),
multiple=True,
size=3,
border="1px solid gray",
width="120px",
),
display="flex",
flex_direction="column",
gap="8px",
align_items="start",
)El rx.el.textarea de Reflex tiene dos atributos que no existen en HTML. Con enter_key_submit=True, Enter envía el formulario y Shift+Enter hace un salto de línea.
Con auto_height=True, la altura crece a medida que el texto se alarga (se usa junto con min_height). enter_key_submit no se puede combinar con on_key_down.
class HtmlFormChatState(rx.State):
messages: list[str] = []
@rx.event
def send(self, form_data: dict):
text = str(form_data.get("message", "")).strip()
if text:
self.messages = [*self.messages, text][-4:]
rx.el.div(
rx.el.ul(
rx.foreach(HtmlFormChatState.messages, lambda m: rx.el.li(m, white_space="pre-wrap")),
list_style_type="disc",
padding_left="1.5em",
),
rx.el.form(
rx.el.textarea(
name="message",
placeholder="Type and press Enter",
enter_key_submit=True,
auto_height=True,
max_length=200,
min_height="40px",
width="100%",
border="1px solid gray",
border_radius="6px",
padding="6px 8px",
),
on_submit=HtmlFormChatState.send,
reset_on_submit=True,
),
max_width="360px",
)output es el lugar donde se muestra el resultado de un cálculo, y en html_for se escriben, separados por espacios, los id de las casillas usadas en el cálculo.
meter es una medida con un rango fijo, como el uso del disco, y progress es el grado de avance de una tarea. Si no das value a progress, muestra el indicador de "en curso".
+ =
class HtmlFormOutputState(rx.State):
a: int = 2
b: int = 3
@rx.event
def change_a(self, value: float):
self.a = int(value)
@rx.event
def change_b(self, value: float):
self.b = int(value)
@rx.var
def total(self) -> int:
return self.a + self.b
rx.el.div(
rx.el.p(
rx.el.input(id="htmlforms_a", type="number", value=HtmlFormOutputState.a, on_change=HtmlFormOutputState.change_a, width="60px", border="1px solid gray"),
" + ",
rx.el.input(id="htmlforms_b", type="number", value=HtmlFormOutputState.b, on_change=HtmlFormOutputState.change_b, width="60px", border="1px solid gray"),
" = ",
rx.el.output(HtmlFormOutputState.total, html_for="htmlforms_a htmlforms_b", name="total", font_weight="bold"),
),
rx.el.label("Disk ", rx.el.meter(value=0.7, low=0.5, high=0.8, optimum=0.2, width="160px")),
rx.el.label("Loading ", rx.el.progress(width="160px")),
display="flex",
flex_direction="column",
gap="8px",
)Las bebidas se agrupan con optgroup, la cantidad es una entrada numérica, la forma de recogida son botones de radio dentro de un fieldset y las peticiones van en un textarea. Al enviar, el State escribe el resumen en output.
class HtmlFormOrderState(rx.State):
summary: str = ""
@rx.event
def place_order(self, form_data: dict):
qty = form_data.get("qty") or "1"
note = str(form_data.get("note", "")).strip() or "none"
self.summary = f"{qty} x {form_data.get('drink')} ({form_data.get('size')}), {form_data.get('pickup')}. Note: {note}"
rx.el.div(
rx.el.form(
rx.el.fieldset(
rx.el.legend("Your order", font_weight="bold"),
rx.el.select(
rx.el.optgroup(rx.el.option("Latte"), rx.el.option("Mocha"), label="Coffee"),
rx.el.optgroup(rx.el.option("Green tea"), rx.el.option("Chai"), label="Tea"),
name="drink",
border="1px solid gray",
padding="4px",
),
rx.el.select(rx.el.option("Small"), rx.el.option("Large"), name="size", border="1px solid gray", padding="4px"),
rx.el.input(name="qty", type="number", min=1, max=9, default_value=1, width="60px", border="1px solid gray", padding="4px"),
display="flex",
gap="8px",
flex_wrap="wrap",
border="1px solid gray",
border_radius="6px",
padding="8px 12px",
),
rx.el.fieldset(
rx.el.legend("Pickup", font_weight="bold"),
rx.el.label(rx.el.input(type="radio", name="pickup", value="for here", default_checked=True), " For here"),
rx.el.label(rx.el.input(type="radio", name="pickup", value="to go"), " To go"),
display="flex",
gap="12px",
border="1px solid gray",
border_radius="6px",
padding="8px 12px",
),
rx.el.textarea(name="note", placeholder="Notes for the barista", rows=2, border="1px solid gray", border_radius="6px", padding="6px 8px"),
rx.el.button("Order", type="submit", padding="6px 14px", border="1px solid gray", border_radius="6px", background=rx.color("indigo", 3)),
on_submit=HtmlFormOrderState.place_order,
display="flex",
flex_direction="column",
gap="10px",
),
rx.el.output(HtmlFormOrderState.summary, display="block", margin_top="10px", font_weight="600"),
max_width="420px",
)Notas del taller
El on_submit de rx.el.form recibe un dict {name: valor}. Cada casilla lleva su name.
Agrupa con fieldset + legend y desactiva todo de golpe con el disabled de fieldset. label se asocia a un id con html_for.
select lleva option·optgroup y se controla con value + on_change. Para varios, multiple·size.
enter_key_submit·auto_height de textarea son atributos de conveniencia que añade Reflex.
meter es una medida que cambia de color con low·high·optimum; progress, el avance; output, el resultado de un cálculo.
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.