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
Elementos HTML

HTML Forms

rx.el.fieldsetrx.el.formrx.el.labelrx.el.legendrx.el.meterrx.el.optgrouprx.el.optionrx.el.outputrx.el.progressrx.el.selectrx.el.textarea

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

Prueba las propiedades

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",
)
Si optimum es menor que low, los valores bajos se consideran buenos; si es mayor que high, los altos. progress es solo una barra de progreso y no cambia de color.

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",
)
rows es el número de líneas visibles. resize es una propiedad CSS que decide si el usuario puede cambiar el tamaño arrastrando la esquina.
PropiedadValoresPor defectoUso
on_submit (form)Event handlerNinguno (solo impide el envío)Recibe un dict con los valores por name
reset_on_submit (form)True / FalseFalseVacía las casillas tras el envío
no_validate (form)True / FalseFalseDesactiva la comprobación de required·pattern del navegador
html_for (label, output)id del elementoNingunoCasilla asociada. Al pulsar la etiqueta se va a esa casilla
disabled (fieldset, select, option, optgroup)True / FalseFalseDesactiva todas las entradas de dentro
value / on_change (select, textarea)Cadena / eventoNingunoEntrada controlada. default_value es no controlada
multiple size (select)bool / enteroFalse / ningunoElegir varios, número de líneas visibles
label (optgroup)CadenaNingunoTítulo del grupo
rows cols max_length (textarea)EnteroNingunoTamaño y límite de caracteres
auto_height enter_key_submit (textarea)True / FalseFalseAltura según el texto, enviar con Enter
value min max low high optimum (meter)Númeromin=0 max=1Medida dentro de un rango
value max (progress)Númeromax=1Grado de avance. Sin value, indica "en curso"

rx.el.form y on_submit

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, legend, label

    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.

    Delivery
    Gift wrap (sold out)
    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",
    )

    select, optgroup, option

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

    textarea: enviar con Enter y altura automática

    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, meter, progress

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

      + = 5

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

      Completar el pedido

      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.

      Your order
      Pickup
      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.

      ← Anterior

      Elementos HTML · HTML Layout

      Siguiente →

      Elementos HTML · HTML Media

      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