Form
Centralized form validation and submission. Supports schema validation (Zod, Valibot, Yup, Joi), custom validators, async submit, nested forms, programmatic API, and more.
Basic Usage
A simple login form with Zod schema validation. Errors appear automatically on each FormField that matches by name.
<script lang="ts">
import { Form, FormField, Input, Button, toast } from 'sv5ui';
import type { FormApi } from 'sv5ui';
import { z } from 'zod';
const schema = z.object({
email: z.email('Invalid email address'),
password: z.string().min(6, 'Password must be at least 6 characters')
});
let state = $state({});
let api = $state<FormApi>();
</script>
<Form {schema} bind:state bind:api onsubmit={() => { toast.success('Form submitted successfully!'); }} class="space-y-4">
<FormField label="Email" name="email" required>
<Input bind:value={state.email} placeholder="you@example.com" leadingIcon="lucide:mail" />
</FormField>
<FormField label="Password" name="password" required>
<Input bind:value={state.password} type="password" placeholder="Enter password" leadingIcon="lucide:lock" />
</FormField>
<Button type="submit" label="Sign In" loading={api?.loading} block />
</Form>Schema Libraries
Form supports Zod, Valibot, Yup (via Standard Schema), and Joi out of the box. Switch between tabs to see each library in action with the same form.
<script lang="ts">
// --- Zod (v3.24+ / v4) ---
import { z } from 'zod';
const zodSchema = z.object({
email: z.email('Invalid email'),
password: z.string().min(8, 'At least 8 characters')
});
// --- Valibot (v1.0+) ---
import * as v from 'valibot';
const valibotSchema = v.object({
email: v.pipe(v.string(), v.email('Invalid email')),
password: v.pipe(v.string(), v.minLength(8, 'At least 8 characters'))
});
// --- Yup (v1.7+) ---
import * as yup from 'yup';
const yupSchema = yup.object({
email: yup.string().email('Invalid email').required('Email is required'),
password: yup.string().min(8, 'At least 8 characters').required('Password is required')
});
// --- Joi (v17+) ---
import Joi from 'joi';
const joiSchema = Joi.object({
email: Joi.string().email({ tlds: false }).required()
.messages({ 'string.email': 'Invalid email', 'string.empty': 'Email is required' }),
password: Joi.string().min(8).required()
.messages({ 'string.min': 'At least 8 characters', 'string.empty': 'Password is required' })
});
</script>
<!-- All four work identically with the Form component -->
<Form schema={zodSchema} bind:state onsubmit={handler} class="space-y-4">...</Form>
<Form schema={valibotSchema} bind:state onsubmit={handler} class="space-y-4">...</Form>
<Form schema={yupSchema} bind:state onsubmit={handler} class="space-y-4">...</Form>
<Form schema={joiSchema} bind:state onsubmit={handler} class="space-y-4">...</Form>Custom Validation
Use the validate prop for custom sync/async validation without a schema library.
<script lang="ts">
import { Form, FormField, Input, Button, toast } from 'sv5ui';
import type { FormError } from 'sv5ui';
let state = $state({ username: '', confirmPassword: '', password: '' });
function validate(st: typeof state): FormError[] {
const errors: FormError[] = [];
if (!st.username) {
errors.push({ name: 'username', message: 'Username is required' });
} else if (st.username.length < 3) {
errors.push({ name: 'username', message: 'Username must be at least 3 characters' });
}
if (!st.password) {
errors.push({ name: 'password', message: 'Password is required' });
}
if (st.password !== st.confirmPassword) {
errors.push({ name: 'confirmPassword', message: 'Passwords do not match' });
}
return errors;
}
</script>
<Form {validate} bind:state onsubmit={() => { toast.success('Registration valid!'); }} class="space-y-4">
<FormField label="Username" name="username" required>
<Input bind:value={state.username} placeholder="Choose a username" />
</FormField>
<FormField label="Password" name="password" required>
<Input bind:value={state.password} type="password" placeholder="Enter password" />
</FormField>
<FormField label="Confirm Password" name="confirmPassword" required>
<Input bind:value={state.confirmPassword} type="password" placeholder="Repeat password" />
</FormField>
<Button type="submit" label="Register" block />
</Form>Validate On Events
Control when validation triggers with validateOn. Default is ['input', 'blur', 'change'].
<script lang="ts">
import { Form, FormField, Input, Button } from 'sv5ui';
import { z } from 'zod';
const schema = z.object({
email: z.email('Invalid email'),
name: z.string().min(2, 'Name is too short')
});
let state = $state({});
</script>
<!-- Only validate on blur (not on every keystroke) -->
<Form {schema} bind:state validateOn={['blur']} onsubmit={() => {}} class="space-y-4">
<FormField label="Name" name="name">
<Input bind:value={state.name} placeholder="Your name" />
</FormField>
<FormField label="Email" name="email">
<Input bind:value={state.email} placeholder="you@example.com" />
</FormField>
<Button type="submit" label="Submit" block />
</Form>Eager Validation
By default, fields only validate after first blur. Set eagerValidation on a FormField to validate immediately on every input.
<script lang="ts">
import { Form, FormField, Input, Button } from 'sv5ui';
import { z } from 'zod';
const schema = z.object({
username: z.string().min(3, 'At least 3 characters'),
email: z.email('Invalid email')
});
let state = $state({});
</script>
<Form {schema} bind:state onsubmit={() => {}} class="space-y-4">
<!-- eagerValidation: validates immediately on input, before first blur -->
<FormField label="Username" name="username" eagerValidation>
<Input bind:value={state.username} placeholder="Type to see instant validation" />
</FormField>
<!-- Default: validates only after first blur -->
<FormField label="Email" name="email">
<Input bind:value={state.email} placeholder="Validates after you leave the field" />
</FormField>
<Button type="submit" label="Submit" block />
</Form>Validate Input Delay
Debounce input validation with validateOnInputDelay. Set at form-level or override per-field.
<script lang="ts">
import { Form, FormField, Input, Button } from 'sv5ui';
import { z } from 'zod';
const schema = z.object({
search: z.string().min(3, 'Enter at least 3 characters'),
code: z.string().regex(/^[A-Z]{3}-\d{3}$/, 'Format: ABC-123')
});
let state = $state({});
</script>
<!-- Global debounce: 500ms -->
<Form {schema} bind:state validateOnInputDelay={500} onsubmit={() => {}} class="space-y-4">
<FormField label="Search" name="search" description="Debounced at 500ms (form-level)">
<Input bind:value={state.search} placeholder="Start typing..." leadingIcon="lucide:search" />
</FormField>
<!-- Per-field override: 1000ms -->
<FormField label="Product Code" name="code" description="Debounced at 1000ms (field-level)" validateOnInputDelay={1000}>
<Input bind:value={state.code} placeholder="ABC-123" />
</FormField>
<Button type="submit" label="Search" block />
</Form>Async Submit
When onsubmit returns a Promise, the form auto-disables and sets loading to true (controlled by loadingAuto). Double-submit is prevented automatically.
<script lang="ts">
import { Form, FormField, Input, Textarea, Button } from 'sv5ui';
import type { FormApi, FormSubmitEvent } from 'sv5ui';
import { z } from 'zod';
const schema = z.object({
title: z.string().min(1, 'Title is required'),
body: z.string().min(10, 'Body must be at least 10 characters')
});
let state = $state({});
let api = $state<FormApi>();
let result = $state('');
async function onsubmit(event: FormSubmitEvent) {
// Simulate API call — form auto-disables during this
await new Promise((r) => setTimeout(r, 2000));
result = JSON.stringify(event.data, null, 2);
}
</script>
<!-- loadingAuto (default: true) disables form during async submit -->
<Form {schema} bind:state bind:api {onsubmit} class="space-y-4">
<FormField label="Title" name="title" required>
<Input bind:value={state.title} placeholder="Post title" />
</FormField>
<FormField label="Body" name="body" required>
<Textarea bind:value={state.body} placeholder="Write something..." rows={3} />
</FormField>
<Button type="submit" label={api?.loading ? 'Saving...' : 'Save Post'} loading={api?.loading} block />
{#if result}
<pre class="mt-2 rounded-lg bg-surface-container p-3 text-sm">{result}</pre>
{/if}
</Form>Programmatic API
Use bind:api to access methods like submit(), validate(), clear(), reset(), and reactive state from outside the form.
<script lang="ts">
import { Form, FormField, Input, Button, toast } from 'sv5ui';
import type { FormApi } from 'sv5ui';
import { z } from 'zod';
const schema = z.object({
firstName: z.string().min(1, 'Required'),
lastName: z.string().min(1, 'Required'),
email: z.email('Invalid email')
});
let state = $state({});
let api = $state<FormApi>();
</script>
<Form {schema} bind:state bind:api onsubmit={() => {}} class="space-y-4">
<FormField label="First Name" name="firstName" required>
<Input bind:value={state.firstName} placeholder="John" />
</FormField>
<FormField label="Last Name" name="lastName" required>
<Input bind:value={state.lastName} placeholder="Doe" />
</FormField>
<FormField label="Email" name="email" required>
<Input bind:value={state.email} placeholder="john@example.com" />
</FormField>
</Form>
<!-- External controls via bind:api -->
<div class="mt-4 flex flex-wrap gap-2">
<Button label="Submit" size="sm" onclick={() => api?.submit()} />
<Button label="Validate" size="sm" variant="outline" onclick={async () => {
const result = await api?.validate({ silent: true });
toast(result ? 'Valid!' : 'Has errors');
}} />
<Button label="Clear Errors" size="sm" variant="outline" color="warning" onclick={() => api?.clear()} />
<Button label="Reset" size="sm" variant="outline" color="error" onclick={() => api?.reset()} />
<Button label="Set Error" size="sm" variant="soft" color="error" onclick={() => {
api?.setErrors([{ name: 'email', message: 'Email already taken' }]);
}} />
</div>
{#if api}
<div class="mt-4 grid grid-cols-2 gap-2 text-sm">
<div>Dirty: <strong>{api.dirty}</strong></div>
<div>Submit count: <strong>{api.submitCount}</strong></div>
<div>Errors: <strong>{api.errors.length}</strong></div>
<div>Loading: <strong>{api.loading}</strong></div>
</div>
{/if}Async Field Validation
Combine schema with async custom validate for checks like username availability. Both run and errors are merged.
<script lang="ts">
import { Form, FormField, Input, Button, toast } from 'sv5ui';
import type { FormError } from 'sv5ui';
import { z } from 'zod';
const takenUsernames = ['admin', 'root', 'user', 'test'];
const schema = z.object({
username: z.string().min(3, 'At least 3 characters'),
email: z.email('Invalid email')
});
let state = $state({});
async function validate(st: { username?: string }): Promise<FormError[]> {
const errors: FormError[] = [];
if (st.username && takenUsernames.includes(st.username.toLowerCase())) {
// Simulate async check (e.g., API call)
await new Promise((r) => setTimeout(r, 500));
errors.push({ name: 'username', message: `"${st.username}" is already taken` });
}
return errors;
}
</script>
<!-- Combine schema + custom async validation -->
<Form {schema} {validate} bind:state onsubmit={() => { toast.success('Registered successfully!'); }} class="space-y-4">
<FormField label="Username" name="username" required hint="Try: admin, root, user, test">
<Input bind:value={state.username} placeholder="Pick a username" leadingIcon="lucide:at-sign" />
</FormField>
<FormField label="Email" name="email" required>
<Input bind:value={state.email} placeholder="you@example.com" leadingIcon="lucide:mail" />
</FormField>
<Button type="submit" label="Register" block />
</Form>Dependent Fields
Use $derived and $effect to create fields that depend on each other. Changing a parent resets its children.
<script lang="ts">
import { Form, FormField, Input, Select, Button, toast } from 'sv5ui';
import { z } from 'zod';
const schema = z.object({
country: z.string().min(1, 'Select a country'),
state: z.string().min(1, 'Select a state'),
city: z.string().min(1, 'Enter a city')
});
let state = $state({ country: '', state: '', city: '' });
const countries = [
{ value: 'us', label: 'United States' },
{ value: 'ca', label: 'Canada' },
{ value: 'uk', label: 'United Kingdom' }
];
const statesByCountry: Record<string, { value: string; label: string }[]> = {
us: [
{ value: 'ca', label: 'California' },
{ value: 'ny', label: 'New York' },
{ value: 'tx', label: 'Texas' }
],
ca: [
{ value: 'on', label: 'Ontario' },
{ value: 'bc', label: 'British Columbia' },
{ value: 'qc', label: 'Quebec' }
],
uk: [
{ value: 'eng', label: 'England' },
{ value: 'sco', label: 'Scotland' },
{ value: 'wal', label: 'Wales' }
]
};
let availableStates = $derived(statesByCountry[state.country] ?? []);
// Reset dependent fields when country changes
$effect(() => {
state.country;
state.state = '';
state.city = '';
});
</script>
<Form {schema} bind:state onsubmit={() => { toast.success('Form submitted successfully!'); }} class="space-y-4">
<FormField label="Country" name="country" required>
<Select items={countries} bind:value={state.country} placeholder="Select country" />
</FormField>
<FormField label="State / Province" name="state" required>
<Select items={availableStates} bind:value={state.state} placeholder="Select state" disabled={!state.country} />
</FormField>
<FormField label="City" name="city" required>
<Input bind:value={state.city} placeholder="Enter city" disabled={!state.state} />
</FormField>
<Button type="submit" label="Save Address" block />
</Form>Nested Forms
Use nested and name to attach a child form to a parent. The child renders as a <div> and its validation, errors, and reset cascade from the parent.
<script lang="ts">
import { Form, FormField, Input, Button, toast } from 'sv5ui';
import { z } from 'zod';
const parentSchema = z.object({
fullName: z.string().min(1, 'Name is required')
});
const addressSchema = z.object({
street: z.string().min(1, 'Street is required'),
zip: z.string().regex(/^\d{5}$/, 'ZIP must be 5 digits')
});
let state = $state({
fullName: '',
address: { street: '', zip: '' }
});
</script>
<!-- Parent form -->
<Form schema={parentSchema} bind:state onsubmit={() => { toast.success('Form submitted successfully!'); }} class="space-y-4">
<FormField label="Full Name" name="fullName" required>
<Input bind:value={state.fullName} placeholder="John Doe" />
</FormField>
<!-- Nested form — renders as <div>, attaches to parent -->
<Form nested name="address" schema={addressSchema}>
<fieldset class="space-y-4 rounded-lg border border-on-surface/15 p-4 pt-0">
<legend class="px-2 text-sm font-medium">Address</legend>
<FormField label="Street" name="street" required>
<Input bind:value={state.address.street} placeholder="123 Main St" />
</FormField>
<FormField label="ZIP Code" name="zip" required>
<Input bind:value={state.address.zip} placeholder="12345" />
</FormField>
</fieldset>
</Form>
<Button type="submit" label="Submit All" block />
</Form>Error Summary
Access all errors via bind:api to render an error summary list at the top of the form.
<script lang="ts">
import { Form, FormField, Input, Button, Alert, toast } from 'sv5ui';
import type { FormApi } from 'sv5ui';
import { z } from 'zod';
const schema = z.object({
name: z.string().min(1, 'Name is required'),
email: z.email('Invalid email address'),
phone: z.string().regex(/^\+?\d{10,15}$/, 'Invalid phone number'),
website: z.url('Invalid URL').or(z.literal(''))
});
let state = $state({});
let api = $state<FormApi>();
</script>
<Form {schema} bind:state bind:api onsubmit={() => { toast.success('Contact saved!'); }} class="space-y-4">
{#if api?.errors.length}
<Alert color="error" icon="lucide:alert-circle" title="Please fix the following errors:">
<ul class="list-inside list-disc text-sm">
{#each api.errors as err}
<li>{err.message}</li>
{/each}
</ul>
</Alert>
{/if}
<FormField label="Name" name="name" required>
<Input bind:value={state.name} placeholder="Full name" />
</FormField>
<FormField label="Email" name="email" required>
<Input bind:value={state.email} placeholder="you@example.com" />
</FormField>
<FormField label="Phone" name="phone" required>
<Input bind:value={state.phone} placeholder="+1234567890" />
</FormField>
<FormField label="Website" name="website">
<Input bind:value={state.website} placeholder="https://example.com" />
</FormField>
<Button type="submit" label="Save Contact" block />
</Form>Array / Repeater Fields
Use a nested <Form> per array item with its own schema. Each nested form validates independently and cascades errors to the parent on submit.
<script lang="ts">
import { Form, FormField, Input, Button, toast } from 'sv5ui';
import { z } from 'zod';
const schema = z.object({
customer: z.string().min(2, 'Customer name is required')
});
const itemSchema = z.object({
description: z.string().min(1, 'Description is required'),
price: z.string().regex(/^\d+(\.\d{1,2})?$/, 'Enter a valid price')
});
interface Item { description: string; price: string }
let state = $state<{ customer: string; items: Item[] }>({
customer: '',
items: [{ description: '', price: '' }]
});
function addItem() {
state.items = [...state.items, { description: '', price: '' }];
}
function removeItem() {
if (state.items.length > 0) {
state.items = state.items.slice(0, -1);
}
}
</script>
<Form {schema} bind:state onsubmit={() => { toast.success('Form submitted successfully!'); }} class="space-y-4">
<FormField label="Customer" name="customer" required>
<Input bind:value={state.customer} placeholder="Wonka Industries" />
</FormField>
<!-- Each array item gets its own nested Form with independent schema -->
{#each state.items as item, i (i)}
<Form nested name={`items.${i}`} schema={itemSchema} class="flex gap-2">
<FormField label={i === 0 ? 'Description' : undefined} name="description" class="flex-1">
<Input bind:value={item.description} placeholder="Item description" size="sm" />
</FormField>
<FormField label={i === 0 ? 'Price' : undefined} name="price" class="w-24">
<Input bind:value={item.price} placeholder="0.00" size="sm" />
</FormField>
</Form>
{/each}
<div class="flex gap-2">
<Button size="sm" variant="outline" label="Add Item" leadingIcon="lucide:plus" onclick={addItem} />
{#if state.items.length > 1}
<Button size="sm" variant="ghost" color="error" label="Remove" leadingIcon="lucide:minus" onclick={removeItem} />
{/if}
</div>
<Button type="submit" label="Submit Invoice" block />
</Form>Disabled
Set disabled to disable the entire form and all its inputs.
<script lang="ts">
import { Form, FormField, Input, Switch, Button } from 'sv5ui';
let disabled = $state(true);
let state = $state({ name: 'John Doe', email: 'john@example.com' });
</script>
<div class="mb-4 flex items-center gap-2">
<Switch bind:checked={disabled} size="sm" />
<span class="text-sm">Form disabled</span>
</div>
<Form {disabled} bind:state onsubmit={() => {}} class="space-y-4">
<FormField label="Name" name="name">
<Input bind:value={state.name} />
</FormField>
<FormField label="Email" name="email">
<Input bind:value={state.email} />
</FormField>
<Button type="submit" label="Save" block />
</Form>Schema Transform
When transform is true (default), Zod .transform() and Valibot pipe transforms are applied to event.data on submit.
<script lang="ts">
import { Form, FormField, Input, Button } from 'sv5ui';
import { z } from 'zod';
const schema = z.object({
email: z.email().transform((v) => v.toLowerCase().trim()),
age: z.string().transform((v) => Number(v)).pipe(z.number().min(18, 'Must be 18+'))
});
let state = $state({});
let result = $state('');
</script>
<!-- transform (default: true) applies schema .transform() on submit -->
<Form {schema} bind:state onsubmit={(e) => { result = JSON.stringify(e.data, null, 2); }} class="space-y-4">
<FormField label="Email" name="email" required description="Will be lowercased and trimmed">
<Input bind:value={state.email} placeholder="USER@Example.COM" />
</FormField>
<FormField label="Age" name="age" required description="String input transformed to number">
<Input bind:value={state.age} placeholder="25" />
</FormField>
<Button type="submit" label="Submit (with transform)" block />
{#if result}
<div class="rounded-lg bg-surface-container p-3">
<p class="mb-1 text-xs font-medium text-on-surface/60">Transformed output:</p>
<pre class="text-sm">{result}</pre>
</div>
{/if}
</Form>Error Event
The onerror callback fires when validation fails on submit. Use it for logging, analytics, or custom error display.
<script lang="ts">
import { Form, FormField, Input, Button, Alert } from 'sv5ui';
import type { FormErrorEvent, FormErrorWithId } from 'sv5ui';
import { z } from 'zod';
const schema = z.object({
email: z.email('Invalid email'),
password: z.string().min(8, 'At least 8 characters')
});
let state = $state({});
let lastErrors = $state<FormErrorWithId[]>([]);
function onerror(event: FormErrorEvent) {
lastErrors = event.errors;
console.log('Validation failed:', event.errors);
}
</script>
<Form {schema} bind:state {onerror} onsubmit={() => { lastErrors = []; }} class="space-y-4">
<FormField label="Email" name="email" required>
<Input bind:value={state.email} placeholder="you@example.com" />
</FormField>
<FormField label="Password" name="password" required>
<Input bind:value={state.password} type="password" placeholder="Min 8 characters" />
</FormField>
<Button type="submit" label="Login" block />
</Form>
{#if lastErrors.length > 0}
<Alert color="warning" icon="lucide:bug" title="onerror fired" class="mt-4">
<pre class="text-xs">{JSON.stringify(lastErrors, null, 2)}</pre>
</Alert>
{/if}All Input Types
Form works seamlessly with all sv5ui input components: Input, Textarea, Select, RadioGroup, Checkbox, Slider, and more.
<script lang="ts">
import { Form, FormField, Input, Textarea, Select, Checkbox, RadioGroup, Slider, Button, toast } from 'sv5ui';
import { z } from 'zod';
const schema = z.object({
name: z.string().min(1, 'Name is required'),
email: z.email('Invalid email'),
bio: z.string().max(200, 'Max 200 characters').optional(),
role: z.string().min(1, 'Select a role'),
experience: z.number().min(0).max(20),
newsletter: z.boolean(),
contactMethod: z.string().min(1, 'Pick one')
});
let state = $state({
name: '', email: '', bio: '', role: '',
experience: 5, newsletter: false, contactMethod: ''
});
const roles = [
{ value: 'dev', label: 'Developer' },
{ value: 'design', label: 'Designer' },
{ value: 'pm', label: 'Product Manager' }
];
const contactMethods = [
{ value: 'email', label: 'Email' },
{ value: 'phone', label: 'Phone' },
{ value: 'slack', label: 'Slack' }
];
</script>
<Form {schema} bind:state onsubmit={() => { toast.success('Form submitted successfully!'); }} class="space-y-4">
<FormField label="Name" name="name" required hint="As it appears on your ID">
<Input bind:value={state.name} placeholder="Jane Smith" leadingIcon="lucide:user" />
</FormField>
<FormField label="Email" name="email" required>
<Input bind:value={state.email} placeholder="jane@company.com" leadingIcon="lucide:mail" />
</FormField>
<FormField label="Bio" name="bio" description="Short description about yourself" help="Max 200 characters">
<Textarea bind:value={state.bio} placeholder="Tell us about yourself..." rows={3} />
</FormField>
<FormField label="Role" name="role" required>
<Select items={roles} bind:value={state.role} placeholder="Select your role" />
</FormField>
<FormField label="Years of Experience" name="experience">
<Slider bind:value={state.experience} min={0} max={20} step={1} />
</FormField>
<FormField label="Preferred Contact" name="contactMethod" required>
<RadioGroup items={contactMethods} bind:value={state.contactMethod} orientation="horizontal" />
</FormField>
<FormField name="newsletter">
<Checkbox bind:checked={state.newsletter} label="Subscribe to newsletter" />
</FormField>
<Button type="submit" label="Save Profile" block />
</Form>Snippets
Named snippets exposed by the Form component.
| Snippet | Description |
|---|---|
children | Default slot — optionally receives { errors, loading } props via {#snippet children({ errors, loading })}. |
UI Slots
Use the ui prop to override classes on internal elements.
| Slot | Description |
|---|---|
root | Root element — <form> by default, <div> when nested=true. |
Props
| Prop | Type | Default |
|---|---|---|
schema | StandardSchemaV1 | JoiSchema | - |
state | Partial<InferInput<S>> | {} |
validate | (state) => FormError[] | Promise<FormError[]> | - |
validateOn | FormInputEvents[] | ['input','blur','change'] |
validateOnInputDelay | number | 300 |
disabled | boolean | false |
loadingAuto | boolean | true |
transform | boolean | true |
nested | boolean | false |
name | string | - |
id | string | number | auto UUID |
api | FormApi | - |
ref | HTMLElement | null | - |
onsubmit | (event: FormSubmitEvent) => void | Promise | - |
onerror | (event: FormErrorEvent) => void | - |
class | string | - |
ui | Partial<Record<'root', Class>> | - |
FormApi (bind:api)
Methods and reactive properties available via bind:api.
| Name | Type | Default |
|---|---|---|
submit() | () => Promise<void> | - |
validate(opts?) | (opts?) => Promise<T | false> | - |
clear(name?) | (name?: string | RegExp) => void | - |
reset() | () => void | - |
setErrors(errs, name?) | (errs: FormError[], name?: string | RegExp) => void | - |
getErrors(name?) | (name?: string | RegExp) => FormErrorWithId[] | - |
errors | FormErrorWithId[] | - |
loading | boolean | - |
disabled | boolean | - |
dirty | boolean | - |
dirtyFields | ReadonlySet<string> | - |
touchedFields | ReadonlySet<string> | - |
blurredFields | ReadonlySet<string> | - |
submitCount | number | - |