Forms

form()#

schema-based with validation rules, dirty/valid tracking, submit with error mapping

wireForm()#

auto-wire existing <form> elements, multi-step wizards, a11y (aria-invalid, aria-describedby)

Files in forms#

File values, maxSize('2MB') / mime(['image/*']) / maxFiles(n), f.formData(), f.preview(key)

Forms#

submitting, submitCount, submitError, result, errors.$form; server errors mapped from non_field_errors/detail/RFC 9457 arrays; double-submit guard

Leaving, drafts, wizards and accessible errors#

f.guard(), draft() and wizard() cover leaving, drafts and multi-step forms, and errors are accessible without a chorus of live regions: one announcement, aria-errormessage, a GOV.UK-style f.summary(). Forms grow (fieldArray, addField, observe), an HTML 422 from Rails or Django is morphed onto the live form with its errors harvested from the markup, and formnovalidate / intent buttons work exactly like they do without JavaScript. Forms separate truth from display: f.issues and f.valid are always right, f.errors is what the user sees, f.canSubmit drives the button, bind:field=${f.field('email')} wires touched / aria / :user-invalid in one attribute, and submit is a status machine with abort, a pending submitter and PRG through the router.

Two-way binding to derived values#

lens(get, set) and bind:value=${[get, set]} bind two-way to any derived or nested value, signals({ … }) names signals after their keys, and the engine warns when ${count.value} is dropped into html`` as a one-time snapshot (E048).

Edit this page on GitHub