Forms

Form workflow.

Validation, pending state and recoverable saves around your own service.

LIVE PREVIEWTry it. It works.

Install the source

Terminal
npx shadcn@latest add https://ui.bld8.dev/r/form.json

Registry setup · Open the playground

Usage

React / TypeScript
const form = useForm({
  initialValues: {name: ""},
  validate: values => ({name: values.name ? undefined : "Enter a name."}),
  onSubmit: (values, {signal}) => saveWorkspace(values, signal)
});
<Form form={form}>
  <Field label="Name" error={form.errors.name}>
    <Input name="name" value={form.values.name}
      onChange={event => form.setField("name", event.target.value)} />
  </Field>
  <Button type="submit" loading={form.pending}>Save</Button>
</Form>

In the workspace or ZIP starter, import components from @bld8/ui and include @bld8/ui/styles.css once. Registry installations use your local bld8/ source path. Wrap overlays in UIProvider.

API & behaviour

useForm accepts synchronous or async validation, an abortable submission callback and onSuccess. Return fieldErrors/error for service validation, or normalised values on success. It prevents duplicate submissions, rejects stale completions, tracks dirty/saved state and focuses the first invalid named field. FormErrorSummary shows a service error; use Field for per-field messages. useUnsavedChanges adds a browser leave warning; in-app dismissal confirmation belongs to your composition. Values should be serialisable. Changing initialValues does not reset a mounted form; call reset explicitly.

Notes to self

Test this component with real content, keyboard input and both themes. The example is a starting point; labels, error handling and behaviour still need to fit the application.