Skip to content
Domphy

Form

@domphy/form provides headless form state for Domphy apps: typed values, per-field and form-level validators (sync + async), touched/blurred/dirty tracking, arrays, and Standard Schema support.

It replaces the ad-hoc FormState / FieldState that used to live in @domphy/ui, so form logic lives in exactly one place.

Install

npm install @domphy/form @domphy/core
<script src="https://unpkg.com/@domphy/form/dist/form.global.js"></script>

@domphy/core is a peer dependency of the adapter only.

Live Example

Adapter

createForm(options) (from @domphy/form/domphy) owns the form; form.field(name, options?) binds one input.

import { createForm } from "@domphy/form/domphy"

const form = createForm<{ email: string }>({
  defaultValues: { email: "" },
  onSubmit: ({ value }) => save(value),
})

const email = form.field<string>("email", {
  validators: { onChange: ({ value }) => (value.includes("@") ? undefined : "Invalid email") },
})

Bind a field to a native input — read value/errors reactively, forward DOM events to the handle:

import { inputText, label, formGroup } from "@domphy/ui"

const Field = {
  div: [
    { label: "Email", $: [label()] },
    {
      input: null,
      $: [inputText()],
      value: (l) => email.value(l),
      onInput: (e) => email.handleChange((e.target as HTMLInputElement).value),
      onBlur: () => email.handleBlur(),
    },
    {
      div: (l) => String(email.errors(l)[0] ?? ""),
      hidden: (l) => email.errors(l).length === 0,
    },
  ],
  $: [formGroup()],
}

Form handle

MemberDescription
values(l) / state(l)Reactive form values / full form state.
canSubmit(l) / isSubmitting(l) / isValid(l) / isSubmitted(l)Reactive flags.
isDirty(l) / isPristine(l)Reactive: any field differs from defaultValues / no field changed.
isTouched(l) / isBlurred(l)Reactive: any field touched / any field blurred.
field<TData>(name, options?)Create and mount a reactive field handle, cached by name — repeat calls for the same name return the same handle.
getFieldValue(field)Read a field value imperatively (no listener).
setFieldValue(field, updater)Set a field value programmatically (triggers onChange validation).
validateField(field, cause?)Manually trigger validation for one field. Cause defaults to "change".
handleSubmit()Run validation and submission. Returns Promise<void>.
reset(values?)Reset to defaults (or given values).
version(l)Reactive change counter — increments on every store flush.
formThe underlying FormApi.
destroy()Unmount the form and all fields; call from _onRemove.

Field handle

MemberDescription
value(l)Reactive value — bind to the input's value/checked.
errors(l) / meta(l)Reactive validation errors / full field meta.
handleChange(value | updater)Update the value (from onInput/onChange). Accepts a direct value or an (prev) => next updater function.
handleBlur()Mark blurred and run blur validators.
setValue(value | updater)Set the value programmatically. Accepts a direct value or an (prev) => next updater function.
validate(cause?)Manually trigger validation. Cause defaults to "change".
pushValue(value)Append to array field.
insertValue(index, value)Insert into array field at index.
replaceValue(index, value)Replace array field item at index.
removeValue(index)Remove array field item at index.
swapValues(a, b)Swap two array field items.
moveValue(a, b)Move array field item from index a to b.
clearValues()Empty the array field.
apiThe underlying FieldApi.

Field and form options (validators, async debouncing, listeners, arrays, Standard Schema) are documented in the Form docs.