Formularios
Estado: EstableCampo de texto
El campo de texto de todos los formularios, envuelto en Field (etiqueta, ayuda, error y aria resueltos). Lleva unidades o íconos dentro ("$", "MXN", "min"), una X para limpiar búsquedas, un ojo que parpadea con resorte para ver la contraseña y, en el registro, un medidor de seguridad que se llena segmento a segmento. Con un form builder toma nombre, valor y error del modelo.
- Resorte
- Formularios
- Form builder
Paquete de 10 clases
Reformer: mínimo 45 min
Paquete de 10 clases
Reformer: mínimo 45 min
app/views/… (la demo de arriba)
<%# En la tarjeta del índice se ven el registro (correo y contraseña con su
medidor) y la búsqueda; en el escenario grande, también precio y duración. %>
<div class="@container w-full max-w-3xl">
<div class="grid gap-x-10 gap-y-5 @xl:grid-cols-2">
<div class="grid content-start gap-4">
<p class="eui-label hidden @xl:block">Crear cuenta</p>
<%= render Ui::InputComponent.new(name: "input_demo[email]", id: "input-demo-email", type: "email", label: "Correo electrónico",
placeholder: "tu@correo.com", autocomplete: "email", required: true) do |input| %>
<% input.with_leading do %>
<%= render Ui::IconComponent.new(:mail) %>
<% end %>
<% end %>
<%= render Ui::InputComponent.new(name: "input_demo[password]", id: "input-demo-password", type: "password", label: "Contraseña",
placeholder: "Al menos 8 caracteres", autocomplete: "new-password", required: true, strength: true) %>
</div>
<div class="grid content-start gap-4">
<p class="eui-label hidden @xl:block">Admin</p>
<%= render Ui::InputComponent.new(name: "q", id: "input-demo-search", type: "search", label: "Buscar cliente", hide_label: true,
placeholder: "Buscar cliente por nombre o correo", value: "Mariana", clearable: true) do |input| %>
<% input.with_leading do %>
<%= render Ui::IconComponent.new(:search) %>
<% end %>
<% end %>
<div class="hidden grid-cols-2 gap-4 @xl:grid">
<%= render Ui::InputComponent.new(name: "input_demo[price]", id: "input-demo-price", type: "number", label: "Precio",
value: 1350, min: 0, step: 50, leading: "$", trailing: "MXN", hint: "Paquete de 10 clases") %>
<%= render Ui::InputComponent.new(name: "input_demo[duration]", id: "input-demo-duration", type: "number", label: "Duración",
value: 40, min: 15, step: 5, trailing: "min", error: "Reformer: mínimo 45 min") %>
</div>
</div>
</div>
</div>Qué hace
- Ui::InputComponent.classes(invalid:, size:) da la misma superficie para un f.text_field propio.
- El ojo es un solo trazo que parpadea con el resorte "responsive"; la contraseña se oculta otra vez al enviar y antes de que Turbo guarde la página en caché.
- El medidor cuenta 8+ caracteres, número y mayúscula (más símbolo o 12+ para el cuarto segmento) y lista lo que falta.
- La X avisa con input y change, así los buscadores en vivo reaccionan; Esc también borra.
- Sin JS es un input nativo: los botones y el medidor solo aparecen cuando el controlador se conecta.
Props
| Nombre | Tipo | Default | Descripción |
|---|---|---|---|
| name | String | nil | Nombre del campo. Con form: + attribute: sale del builder. |
| type | String | "text" | email, password, tel, url, search, number, date, time, datetime (= datetime-local)… |
| label | String | nil | Etiqueta visible. Sin ella el campo queda nombrado por placeholder (etiqueta oculta). |
| value / placeholder | String | nil | Valor inicial y texto de ejemplo. Fechas y horas se formatean solas. |
| form: + attribute: | FormBuilder, Symbol | nil | Nombre, id, valor y error salen del modelo (usa f.email_field, f.number_field…). |
| hint / error | String | nil | Ayuda y error (el error del modelo se toma solo con form:). |
| required / optional / disabled | Boolean | false | Asterisco, marca de Opcional o deshabilitado. |
| size | :sm | :md | :lg | :md | Alto del control (sigue el dial de densidad). |
| leading: / trailing: | String | nil | Texto corto dentro del campo: "$", "MXN", "min", "@". Se lee como descripción. |
| with_leading / with_trailing | slot | — | Un ícono de 16px dentro del campo (decorativo). |
| clearable | Boolean | String | false | Botón X para borrar; con String, su nombre accesible ("Borrar búsqueda" por defecto en search). |
| strength | Boolean | false | Solo password: medidor de seguridad para contraseñas nuevas. |
| reveal | Boolean | true | Solo password: botón para mostrar/ocultar. |
| **attrs | Hash | {} | id, autocomplete, min, step, data, aria… van al <input>; class: se suma a la superficie. |
Accesibilidad
- La etiqueta, la ayuda y el error se enlazan con for, aria-describedby y aria-invalid (Field).
- El botón del ojo se llama "Mostrar contraseña" y dice su estado con aria-pressed.
- La X tiene nombre accesible y regresa el foco al campo.
- El nivel de seguridad y lo que falta se anuncian (polite) cuando dejas de teclear, no en cada letra.
- Las unidades ("$", "MXN", "min") se leen como descripción del campo.