Cómo funcionan los formularios
Los seis controles de formulario — ch-checkbox, ch-input, ch-radio, ch-select, ch-switch y
ch-textarea — son form-associated custom elements. Dentro de un <form> se comportan como controles nativos, sin JavaScript de por
medio:
- Su valor/estado se envía en
FormDatay en el submit (por suname). - Aparecen en
form.elementsyform.checkValidity()los ve. - Un campo
requiredvacío es inválido (valueMissing) y bloquea el submit. - El host matchea
:invalid/:valid, así puedes estilarlo desde tu CSS. form.reset()restaura el valor o estado inicial.- Un
<fieldset disabled>deshabilita los controles que contiene y excluye sus valores.
Es un cambio de comportamiento: en versiones anteriores estos controles no participaban en el formulario. Si compensabas esa ausencia a mano (por ejemplo, con
hidden inputs alimentando FormData), hay que quitar ese trabajo manual para no duplicar valores.
Lo mínimo
Un formulario con un solo campo, leído con JavaScript puro:
<form id="contacto">
<ch-input name="email" label="Correo" type="email" required></ch-input>
<ch-button id="enviar">Enviar</ch-button>
</form>
const form = document.getElementById('contacto');
const submit = document.getElementById('enviar');
// ch-button no puede disparar el submit por sí solo (vive en su shadow
// root): conecta chClick con requestSubmit(), que valida y dispara submit.
submit.addEventListener('chClick', () => form.requestSubmit());
form.addEventListener('submit', (event) => {
event.preventDefault(); // sin backend real, acá solo leemos los datos
const data = Object.fromEntries(new FormData(form));
console.log(data); // { email: 'tu@email.com' }
});
Ejemplo: formulario de login
Correo y contraseña con required. El navegador valida antes de disparar submit: si un campo obligatorio está vacío, muestra el mensaje y no se
llega al handler.
HTML
<form id="login-form">
<ch-input name="email" label="Correo electrónico" type="email" required error-message="Ingresa un correo válido"></ch-input>
<ch-input name="password" label="Contraseña" type="password" required error-message="Ingresa tu contraseña"></ch-input>
<ch-button id="login-submit">Entrar</ch-button>
</form>
JavaScript
const form = document.getElementById('login-form');
const output = document.getElementById('login-result');
const submit = document.getElementById('login-submit');
// ch-button no puede disparar el submit por sí solo: conecta chClick con
// requestSubmit(), que valida y dispara `submit` si el formulario es válido.
submit.addEventListener('chClick', () => form.requestSubmit());
form.addEventListener('submit', (event) => {
event.preventDefault(); // en este demo no hay backend
const data = Object.fromEntries(new FormData(form));
// fetch('/api/login', { method: 'POST', body: JSON.stringify(data) })
output.textContent = JSON.stringify(data, null, 2);
});
Notas
-
Botón de submit.
ch-buttonrenderiza un<button type="button">dentro de su shadow root, así que no dispara el submit por sí solo. ConectachClickconform.requestSubmit(): ese método corre la validación nativa y disparasubmitsi el formulario es válido:document.getElementById('entrar').addEventListener('chClick', () => { document.getElementById('login-form').requestSubmit(); }); -
Resaltado del campo inválido. Los componentes pintan el borde del control en color de advertencia cuando el campo es inválido después de que
el usuario terminó la interacción — al salir del campo (
focusout) o al confirmar el valor (change) — o ante un intento de submit (eventoinvalid). Un campo con foco aún no se resalta mientras el usuario lo está editando. Internamente se marca al terminar la interacción, y el estilo se resuelve con la validez nativa:
Desde tu CSS también puedes apuntar al host con las mismas pseudoclases (p. ej./* dentro del componente */ :host([data-touched]:invalid) .input, :host(:user-invalid) .input { border-color: var(--color-status-warning); }ch-input[data-touched]:invalid) para estilos propios.:user-invalidhace lo mismo en navegadores que lo reportan sobre custom elements; el atributodata-touchedcubre el resto. -
Mensaje de error inline. El texto rojo bajo el campo se renderiza cuando pasas
invalid+error-message(por ejemplo, desde la validación del servidor). Elrequiredvacío valida solo por la API nativa: el navegador muestra elvalidationMessageen el control inválido y bloquea el submit. -
Validación de formato. El
type(p. ej.email) se aplica al input interno. La validez del host reflejarequiredyinvalid/error-message; la validación de formato deltypetodavía no se propaga a la constraint validation del host. -
La API de constraint validation de estos componentes vive en
element.internals(checkValidity(),validationMessage,validity,willValidate). Para consumidores el camino habitual esform.checkValidity(),new FormData(form)y CSS:invalid. -
Controles sin
nameno se envían en el submit, igual que los controles nativos.