Form
Form container with validation timing, an error summary, server errors, dirty tracking and async submit.
c2-form wraps a native <form> and its c2-form-fields. The native form stays in charge of its controls, so FormData, reset, requestSubmit, <fieldset disabled> and framework bindings work as they do without it. On a submit attempt it suppresses the browser’s validation bubbles, shows every field’s error, and focuses either an error summary (two or more errors, each linking to its control) or the one invalid control. When every control is valid it runs validator for cross-field checks, then fires valid-submit instead of submitting the page.
valid-submit carries the FormData, a plain values object and waitUntil(promise): while the promise is pending the form is in :state(submitting) and a c2-button submitter shows its running spinner. A promise that resolves makes the current values the new pristine state; one that rejects with { name: message } shows those errors on their fields. Server errors can also come from the errors attribute or setErrors(); each clears when the user edits its control. dirty-change fires when the values start or stop differing from the pristine state, and warn-unsaved asks before the page unloads while they do.
necessity and validate-on set the defaults of every field inside. The form is a grid of its children: --c2-form--columns gives it columns and --c2-form-field--grid-column: 1 / -1 spans a field across them.
Import
import '@c2n/components/form'
import '@c2n/components/form-field'Usage
Saving
const form = document.querySelector('c2-form')!
form.addEventListener('valid-submit', (event) => {
// Rejecting with { name: message } shows those errors on their fields.
event.detail.waitUntil(api.saveAccount(event.detail.values))
})
form.addEventListener('dirty-change', (event) => {
saveBar.hidden = !event.detail.dirty
})
// Checks across fields, after every control passes its own constraints.
form.validator = (values) => (values.password === values.confirm ? {} : { confirm: 'The passwords do not match.' })