Skip to content

Forms

Forms allow users to fill and submit data to your application, sometimes they are given feedback along the way to help them achieve that.

Assuming you’ve followed the other guides and have created a few input components, you can now use them to build a form. Formwerk builds on the native form element but it is not required.

  • Value tracking and submission handling.
  • Nested fields and arrays support.
  • Controlled and uncontrolled fields.
  • Multi-layered validation with both HTML attributes or Standard Schemas.
  • Aggregated state for validation, dirty, touched, and more.
  • Type safety for form data and submitted data.
  • Scrolling to the first invalid field after submission.
  • Submitted data can be consumed as a plain object, JSON, or FormData object.

You will be using the useForm composable to create a form context in the current component. This effectively marks the component as a form, meaning you can only use useForm once per component.

This is the most basic form you can create with Formwerk:

import { useForm } from '@formwerk/core';
const { handleSubmit } = useForm();
const onSubmit = handleSubmit((data) => {
console.log(data);
});

It doesn’t look like much, but already a lot is being done for you behind the scenes. The useForm composable creates a reactive form context that does the following among other things:

  • Tracks and collects the values of all input fields within the form.
  • Tracks the validity of each field and the overall form validity.
  • Provides a handleSubmit function that you can use to submit the form.

Here is an example with some input fields we already created from the previous guides:

<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
import Checkbox from './Checkbox.vue';
const { handleSubmit } = useForm();
const onSubmit = handleSubmit((data) => {
alert(JSON.stringify(data.toObject(), null, 2));
});
</script>
<template>
<form @submit="onSubmit" novalidate>
<TextField name="email" label="Email" type="email" required />
<TextField name="password" label="Password" type="password" required />
<Checkbox label="Remember me" name="rememberMe" />
<button type="submit">Submit</button>
</form>
</template>

You may have noticed that we passed the name prop to the input fields in the previous example. This is because Formwerk uses the name prop to identify the fields in the form and uses it to build the form data object that will eventually be submitted.

Passing the name prop to the field marks it as “controlled”, as in it is being tracked by the form and contributes its state and value to the form data object.

Now if you want to do the opposite, which is to not have the field be tracked by the form, then you can simply skip passing the name prop. This matches the behavior of FormData objects and native form submission behavior.

Here is an example where a non-controlled field can be useful. In this example, we toggle the visibility of the billingAddress field based on the value of the sameAsShipping field, but we don’t want to submit the latter.

<script setup lang="ts">
import { ref } from 'vue';
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
import Checkbox from './Checkbox.vue';
const { handleSubmit } = useForm();
const isSameAsBilling = ref(false);
const onSubmit = handleSubmit((data) => {
const json = data.toObject();
if (isSameAsBilling.value) {
json.billingAddress = json.shippingAddress;
}
alert(JSON.stringify(json, null, 2));
});
</script>
<template>
<form @submit="onSubmit" novalidate>
<TextField name="shippingAddress" label="Shipping Address" required />
<TextField
v-if="!isSameAsBilling"
name="billingAddress"
label="Billing Address"
required
/>
<Checkbox label="Same as shipping" v-model="isSameAsBilling" />
<button type="submit">Submit</button>
</form>
</template>

Formwerk supports nested fields by using the . character in the name prop. This allows you to create nested objects in the form data object to structure your data however you need. Having numeric path names will result in arrays being created instead of objects.

Here is an example with both nested fields and arrays:

<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
import Checkbox from './Checkbox.vue';
const { handleSubmit } = useForm();
const onSubmit = handleSubmit((data) => {
alert(JSON.stringify(data.toObject(), null, 2));
});
</script>
<template>
<form @submit="onSubmit" novalidate>
<TextField name="socials.github" label="GitHub " type="url" required />
<TextField name="socials.twitter" label="Twitter " type="url" required />
<TextField name="socials.discord" label="Discord" type="url" required />
<TextField name="customLinks.0" label="Custom link 1" type="url" />
<TextField name="customLinks.1" label="Custom Link 2" type="url" />
<button type="submit">Submit</button>
</form>
</template>

You noticed that the values of the form are collected and passed for you in the data object in the previous examples.

The previous examples used the handleSubmit function to submit the form. This function doesn’t require you to use a form element nor does it require you to use it with a submit event. You can use it with any event or even call it directly.

The handleSubmit function takes a callback function that will be called with the data object when the form is submitted. The callback is run only if the form is valid; otherwise, it does nothing.

Here is an example where we just call the submission handler directly:

<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
const { handleSubmit } = useForm();
const onSubmit = handleSubmit((data) => {
alert(JSON.stringify(data.toObject(), null, 2));
});
function onClick() {
onSubmit();
}
</script>
<template>
<TextField name="field" label="Your field" value="Press 👇" />
<button @click="onClick">Press me</button>
</template>

The most common way to get the form data is to call the toObject method on the data object. This method returns a plain JavaScript object with the form data as you’ve seen in the previous examples.

import { useForm } from '@formwerk/core';
const { handleSubmit } = useForm();
const onSubmit = handleSubmit((data) => {
data.toObject(); // { email: '...', password: '...', rememberMe: true }
});

The toJSON method returns a JSON-serializable object with the form data. While this often matches the structure from toObject, JSON has some limitations compared to JavaScript objects. For example, JSON cannot represent:

  • undefined values
  • Date objects (they get converted to strings)
  • File objects
  • Functions
  • BigInt values
  • Symbol values

The toJSON method handles converting these values into JSON-safe equivalents automatically.

import { useForm } from '@formwerk/core';
const { handleSubmit } = useForm();
const onSubmit = handleSubmit(async (data) => {
const response = await fetch('https://example.org/post', {
body: JSON.stringify(data.toJSON()),
});
});

If you plan to stringify the form data for use with something like fetch or axios, then you can omit the toJSON and call JSON.stringify directly on the data object, which will call toJSON under the hood.

const onSubmit = handleSubmit(async (data) => {
const response = await fetch('https://example.org/post', {
body: JSON.stringify(data.toJSON()),
body: JSON.stringify(data),
});
});

The toJSON method is fully typed to match the JSON-serialized structure of your form data. The types will automatically handle non-serializable values like undefined, Date objects, and File objects in the type system, ensuring the types match what actually gets serialized to JSON.

If you need to submit the form data as a FormData object, you can call the toFormData method instead.

This method returns a FormData object that you can use to submit the form data to traditional form endpoints or APIs. It becomes especially useful when submitting files since they cannot be transported in JSON.

import { useForm } from '@formwerk/core';
const { handleSubmit } = useForm();
const onSubmit = handleSubmit((data) => {
data.toFormData(); // FormData
});

If you prefer to not handle submissions with JavaScript and instead want to rely on native form submissions, which is common with non-JS server-rendered applications like Rails (Ruby) or Laravel (PHP) applications, you can use the formProps object that is returned by the useForm composable to bind the form props to the form element. It will enhance the native submission cycle with the same features as with the handleSubmit function.

When you submit a form bound to the formProps object:

  1. The form submit event will be prevented.
  2. The form data will be collected and validated.
  3. If invalid, the form will not be submitted, and the flow ends.
  4. If valid, the form will be submitted using the native form submission cycle.

Here is an example of how to use formProps. The example will submit the data to another page that will list the submitted values. Typically, your backend endpoint would be handling the form submission.

<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
import Checkbox from './Checkbox.vue';
const { formProps } = useForm();
</script>
<template>
<form v-bind="formProps" target="_blank" action="/form-d">
<TextField name="email" label="Email" type="email" required />
<TextField name="password" label="Password" type="password" required />
<Checkbox label="Remember me" name="rememberMe" />
<button type="submit">Submit</button>
</form>
</template>

Forms and Fields expose several properties related to the submission state. They can be useful to build certain UI behaviors like showing submit progress spinners or disabling the submit button while the form is being submitted with an async handler.

You can check the submission status with the isSubmitting property. This property is true when the form is being submitted and false otherwise. This is useful when you want to show a loading spinner or disable the submit button while the form is being submitted with an async handler.

<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
const { handleSubmit, isSubmitting } = useForm();
const onSubmit = handleSubmit(async (data) => {
await new Promise((resolve) => setTimeout(resolve, 2000));
alert(JSON.stringify(data.toObject(), null, 2));
});
</script>
<template>
<form @submit="onSubmit" novalidate>
<TextField name="email" label="Email" type="email" required />
<TextField name="password" label="Password" type="password" required />
<button :disabled="isSubmitting" type="submit">Submit</button>
</form>
</template>

The wasSubmitted property is true if the form was submitted and the handler was called without any errors thrown. This is useful when you want to show a success message or perform some custom logic after the form has been submitted.

<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
const { handleSubmit, wasSubmitted } = useForm();
const onSubmit = handleSubmit(async (data) => {
console.log(JSON.stringify(data.toObject(), null, 2));
});
</script>
<template>
<form v-if="!wasSubmitted" @submit="onSubmit" novalidate>
<TextField name="email" label="Email" type="email" required />
<TextField name="password" label="Password" type="password" required />
<button type="submit">Submit</button>
</form>
<p v-else>Form was submitted</p>
</template>

This state is reset when the form is reset.

The submitAttemptsCount property returns the number of times the form has been submitted regardless of whether it was valid or not.

This can be useful when you want to disable certain UI elements, or show some feedback to the user. You might even want to gather analytics! maybe your form is too hard?

<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
const { handleSubmit, submitAttemptsCount } = useForm();
const onSubmit = handleSubmit(async (data) => {
console.log(JSON.stringify(data.toObject(), null, 2));
});
</script>
<template>
<p>Submit attempts: {{ submitAttemptsCount }}</p>
<form @submit="onSubmit" novalidate>
<TextField name="email" label="Email" type="email" required />
<TextField name="password" label="Password" type="password" required />
<button type="submit">Submit</button>
</form>
</template>

This state is reset when the form is reset.

The isSubmitAttempted property is true if the form was submitted, but unlike wasSubmitted, it turns true even if the form is invalid.

import { useForm } from '@formwerk/core';
const { handleSubmit, isSubmitAttempted } = useForm();
const onSubmit = handleSubmit((data) => {
console.log(JSON.stringify(data.toObject(), null, 2));
});

By default, Formwerk will scroll to the first invalid field when the form is submitted.

The scrolling is performed with the Element.scrollIntoView method with smooth behavior by default. You can override that by passing ScrollViewOptions to the scrollToInvalidFieldOnSubmit option.

import { useForm } from '@formwerk/core';
useForm({
scrollToInvalidFieldOnSubmit: {
behavior: 'instant', // default is 'smooth'
block: 'center', // default is 'center'
inline: 'start', // default is 'start'
},
});

You can see it in action in the following example. Scroll all the way down to see the form submit button and then click it to see the invalid field being scrolled into view.

<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
const { handleSubmit, isSubmitting } = useForm();
const onSubmit = handleSubmit((data) => {
alert(JSON.stringify(data.toObject(), null, 2));
});
</script>
<template>
<form @submit="onSubmit" novalidate>
<TextField name="email" label="Email" type="email" required />
<TextField name="password" label="Password" type="password" required />
<button :disabled="isSubmitting" type="submit">Submit</button>
</form>
</template>
<style>
form {
display: flex;
flex-direction: column;
/* This is to make the view scrollable */
gap: 500px;
}
</style>

This behavior can be disabled by setting the scrollToInvalidFieldOnSubmit option to false when creating the form.

import { useForm } from '@formwerk/core';
useForm({
scrollToInvalidFieldOnSubmit: false,
});

Forms track the touched state of each field in the form. A field is considered touched when the user interacts with it, which means if they have focused and blurred the field at least once. In addition to blurring, whenever the form is submitted, all fields are marked as touched.

The form also tracks the overall touched state of the form, which is true if any field in the form has been touched.

Each field composable returns an isTouched property. useForm exposes its own isTouched method that you can use to check if the form has been interacted with or if a field has been touched.

<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
const { handleSubmit, isTouched } = useForm();
const onSubmit = handleSubmit((data) => {
console.log('All fields should be touched now');
});
</script>
<template>
<form @submit="onSubmit" novalidate>
<TextField name="email" label="Email" type="email" />
<TextField name="password" label="Password" type="password" />
<pre>Email Touched: {{ isTouched('email') }}</pre>
<pre>Password Touched: {{ isTouched('password') }}</pre>
<pre>Form Touched: {{ isTouched() }}</pre>
<button type="submit">Submit</button>
</form>
</template>

You can set the touched state of fields manually with the setTouched function.

import { useForm } from '@formwerk/core';
const { setTouched } = useForm();
function onFieldBlur() {
setTouched('email', true);
// Or set all fields to touched
setTouched(true);
}

Forms also track the dirty state of each field in the form. A field is considered dirty when its value has changed from the initial value. The form also tracks the overall dirty state of the form, which is true if any field in the form has been modified.

<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
const { isDirty } = useForm();
</script>
<template>
<TextField name="email" label="Email" type="email" />
<TextField name="password" label="Password" type="password" />
<pre>Email Dirty: {{ isDirty('email') }}</pre>
<pre>Password Dirty: {{ isDirty('password') }}</pre>
<pre>Form Dirty: {{ isDirty() }}</pre>
</template>

The dirty state is computed. There is no way to set it manually, but you can reset the form to its initial values or a new set of values to influence the dirty state.

As you’ve seen from field guides, many fields can be validated with either HTML constraints via attributes like required, min, max, etc., or with Standard Schema objects.

HTML constraints are always field-level. They are useful for dynamic fields, but at the same time, they are more accessible to users, which is why it is recommended to use them whenever possible for basic validations.

For advanced cases, you can use Standard Schemas, which can be both field-level or form-level.

If you want to completely disable HTML constraints for the form, you can pass the disableHtmlValidation option to useForm:

import { useForm } from '@formwerk/core';
useForm({
disableHtmlValidation: true,
});

Form-level Validation with Standard Schemas

Section titled “Form-level Validation with Standard Schemas”

But you can also provide a form-level Standard Schema to useForm to validate the entire form as a whole. Form-level schemas are useful for forms where the fields are known beforehand.

Here is an example of a form with a Standard Schema:

<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
import { z } from 'zod';
const { handleSubmit } = useForm({
schema: z.object({
email: z.string().email(),
password: z.string().min(8),
}),
});
const onSubmit = handleSubmit((data) => {
alert(JSON.stringify(data.toObject(), null, 2));
});
</script>
<template>
<form @submit="onSubmit" novalidate>
<TextField name="email" label="Email" />
<TextField name="password" label="Password" type="password" />
<button type="submit">Submit</button>
</form>
</template>

For more information on Standard Schemas and which libraries are supported, visit the project’s GitHub page.

Let’s say you have a mix of validations in place. You have a field with some HTML constraints and a schema that validates that field at the same time. Let’s throw in a form-level schema that validates the form, including that field.

That field now has three sources of validation. How does that work?

Formwerk prioritizes the validation sources in the following order:

  1. HTML Constraints are checked first. Only if they are valid, continue to the next step.
  2. Field-level Standard Schema is checked next. Only if it is valid, continue to the next step.
  3. Form-level Standard Schema is checked last.

This keeps the validation process consistent and predictable. At the same time, it is also efficient, as you won’t have to re-validate the whole form if a field-level validation fails for that field. You can think of it as a merged validation approach, but it is more of a cascading validation behavior where it cascades upwards to the form level.

The only thing you need to be careful of is to not have conflicting validations between the different sources, as this can cause the field to never be valid.

Here is an example for a field with all validation sources:

<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
import { z } from 'zod';
const { handleSubmit } = useForm({
schema: z.object({
field: z.string().max(8),
}),
});
const onSubmit = handleSubmit((data) => {
alert(JSON.stringify(data.toObject(), null, 2));
});
</script>
<template>
<form @submit="onSubmit" novalidate>
<TextField name="field" label="Field" min-length="3" required />
<button type="submit">Submit</button>
</form>
</template>

You can even have a fourth source of validation with Form Groups.

If you have followed the field guides, you know that fields are responsible for displaying their own errors. But what if you want to display the form errors in a single place, or maybe you just need access to errors to perform some custom logic?

There are three ways to access errors with useForm:

  • getError to get the error of a specific field.
  • getErrors to get all errors in the form grouped by field.
  • displayError to display the error of a specific field if it has been touched.

The getError function returns the error of a specific field. If the field has no error, it returns undefined.

<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
import { z } from 'zod';
const { handleSubmit, getError } = useForm({
schema: z.object({
url: z.string().url().max(8),
email: z.string().email(),
}),
});
</script>
<template>
<TextField name="url" label="URL" required />
<TextField name="email" label="Email" required />
<ul>
<li>URL Error: {{ getError('url') }}</li>
<li>Email Error: {{ getError('email') }}</li>
</ul>
</template>

Unlike validation errors which are mostly “live” and react to the values changing regardless of when you display them, submit errors are only populated when the form is submitted. This is useful if you want to only show errors after submits rather than live.

Each field exposes submitErrorMessage and submitErrors, using these will only display errors after the form is submitted.

import { useTextField } from '@formwerk/core';
const { submitErrorMessage, submitErrors } = useTextField({
// ...
});

Forms also expose getSubmitError and getSubmitErrors to get the submit error of a specific field or all fields respectively, if you need access to them on the form level.

Form state can be reset with the reset function. Calling this function will reset the current values back to the initial values, revert the touched state for all fields back to false, and clear any custom errors.

<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
import Checkbox from './Checkbox.vue';
const { handleSubmit, reset } = useForm();
const onSubmit = handleSubmit((data) => {
alert(JSON.stringify(data.toObject(), null, 2));
});
function onResetClick() {
reset();
}
</script>
<template>
<form @submit="onSubmit" novalidate>
<TextField name="email" label="Email" type="email" required />
<TextField name="password" label="Password" type="password" required />
<Checkbox label="Remember me" name="rememberMe" />
<button type="submit">Submit</button>
<button type="button" @click="onResetClick">Reset</button>
</form>
</template>

Notice that even though we called reset, the errors are still displayed. By default, reset re-validates the form afterward. This is to ensure that the validation state of the fields matches their actual validity.

You should consider using isTouched or displayError to show errors only when the field has been interacted with, which would eliminate this caveat. Alternatively, you can disable this behavior by passing revalidate: false to the reset function.

import { useForm } from '@formwerk/core';
const { reset } = useForm();
function onReset() {
reset({ revalidate: false });
}

You can also reset the form to a specific state by passing a ResetState object to the reset function. This object can contain the following properties:

  • values: The new form values.
  • touched: The new touched state for each field.
<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
const { handleSubmit, reset } = useForm();
const onSubmit = handleSubmit((data) => {
alert(JSON.stringify(data.toObject(), null, 2));
});
function onResetClick() {
reset({
value: {
email: 'hello@formwerk.dev',
password: 'p@$$w0rd',
},
touched: {
email: true,
password: false,
},
});
}
</script>
<template>
<TextField name="email" label="Email" type="email" required />
<TextField name="password" label="Password" type="password" required />
<button @click="onResetClick">Reset</button>
</template>

Lastly, the value setting behavior by default uses a replace strategy. This means that the values are replaced with the new values, and any unspecified values will be considered undefined.

If you want to merge the new values with the existing initial values, you can pass behavior: 'merge' to the reset function as the second argument.

import { useForm } from '@formwerk/core';
const { reset } = useForm();
function onReset() {
reset(
{
// values and stuff...
},
{ behavior: 'merge' },
);
}

You can also use handleReset() to create an event handler that responds to the native reset event.

<script setup lang="ts">
import { useForm } from '@formwerk/core';
import TextField from './TextField.vue';
const { handleSubmit, handleReset } = useForm();
const onSubmit = handleSubmit((data) => {
alert(JSON.stringify(data.toObject(), null, 2));
});
const onReset = handleReset(() => {
alert('after reset');
});
</script>
<template>
<form @reset="onReset" @submit="onSubmit" novalidate>
<TextField name="email" label="Email" type="email" required />
<TextField name="password" label="Password" type="password" required />
<button type="submit">Submit</button>
<button type="reset">Reset</button>
</form>
</template>

Forms support typing your form values with TypeScript. This is done through a couple of generic type parameters.

The useForm composable signature is roughly typed as:

function useForm<
TSchema extends StandardSchema<FormObject>,
TInput extends FormObject = FormObject,
TOutput extends FormObject = TInput,
>();

Let’s break down the generic type parameters:

  • TSchema: The type of the form schema if a Standard Schema is used.
  • TInput: The type of the form input values. These represent the current values of the form fields without any validation or transformations applied. We also refer to those as “input” types.
  • TOutput: The type of the form output values. These represent the values that would be submitted. That means validation and transformations have already been applied.

The distinction between input and output types is important because it helps you avoid re-checking values that have already been validated in runtime to satisfy TypeScript.

You can type a form by either providing initialValues to infer the input type.

const { values, handleSubmit } = useForm({
initialValues: { email: '' },
});
values; // { email?: string | undefined }

However, this does not provide you with output types, meaning when submitting the form, the email field would still be typed as string | undefined.

In order to get output types, we export a utility type called FormSchema that you can use to type both the input and output values. By default, the input type is assumed to be a partial of the output type.

import { type FormSchema, useForm } from '@formwerk/core';
// Input type is assumed to be a partial of the output type
type LoginForm = FormSchema<{ email: string }>;
const { handleSubmit, values } = useForm<LoginForm>();
values; // { email: string | undefined }
const onSubmit = handleSubmit((data) => {
console.log(data.toObject()); // { email: string }
});

If you want to explicitly define both the input and output types, you can do so by passing a second generic argument to the FormSchema type. The first being the input type and the second being the output type.

import { type FormSchema, useForm } from '@formwerk/core';
type LoginForm = FormSchema<
{ email: string },
{ email: string; token: string }
>;
const { handleSubmit, values } = useForm<LoginForm>();
values; // { email: string | undefined; }
const onSubmit = handleSubmit((data) => {
console.log(data.toObject()); // { email: string; token: string }
});

We only recommend using this approach for simple forms with a few fields, or if the types are automatically generated from an API schema like GraphQL or OpenAPI specs.

By providing a Standard Schema to the schema prop, the form will infer both the input and output types automatically.

import { z } from 'zod';
const { values, handleSubmit } = useForm({
schema: z.object({ email: z.string().email() }),
});
values; // { email: string | undefined }
const onSubmit = handleSubmit((data) => {
data.toObject(); // { email: string }
});

For getting the most out of type safety, it is recommended to use Standard Schemas over manually providing types via the initialValues prop.

You may need to access the form context from within a component that is a child of the form. Common examples are button components that may need to be aware of the submitting state or the dirty state.

To do this, you can use the useFormContext composable.

import { useFormContext } from '@formwerk/core';
const { isSubmitting } = useFormContext();

These are the properties that can be passed to the useForm composable.

NameTypeDescription
disabledWhether the form is disabled.
disableHtmlValidationWhether HTML5 validation should be disabled for this form.
idThe form's unique identifier.
initialDirtyThe initial dirty state for form fields.
initialTouchedThe initial touched state for form fields.
initialValues
schemaThe validation schema for the form.
scrollToInvalidFieldOnSubmitWhether the form should scroll to the first invalid field on invalid submission.

These are the properties in the object returned by the useForm composable.

NameTypeDescription
contextThe form context object, for internal use.
displayErrorDisplays the errors for a form field.
formPropsThe form props.
getErrorGet the error for a form field.
getErrorsGet the errors for a form field, or the
getIssuesGet the issues for a form field.
getSubmitErrorGet the submit error for a form field.
getSubmitErrorsGet the submit errors for a form field.
getValue
TPath extends Path<TInput>>(path: TPath) => PathValue<TInput, TPath
Gets the value of a field or a path.
handleReset
(afterReset?: () => any) => (e?: Event) => Promise<void>
Handle form reset.
handleSubmit
(onSubmit: (values: ConsumableData<TInput>) => any) => (e?: Event) => Promise<void>
Handle form submission.
isDirtyChecks if the form is dirty, which is true if any field's value has changed from the initial values. Accepts an optional path to check if a specific form path is dirty.
isDisabledWhether the form is disabled.
isSubmitAttemptedWhether the form was submitted, wether the validity or the submission was successful or not.
isSubmittingWhether the form is submitting.
isTouchedChecks if the form is touched, which is true if any field has been touched. Accepts an optional path to check if a specific form path is touched.
isValidChecks if the form is valid, or if a form path is valid. Validity is defined as the absence of errors.
reset
{ (): Promise<void>; (state: Partial<ResetState<TInput>>, opts?: SetValueOptions): Promise<void>; <TPath>(path: TPath): Promise<void>; <TPath extends Path<...>>(path: TPath, state: Partial<...>, opts?: SetValueOptions): Promise<...>; }
Reset the form to its initial values
setErrors
{ <TPath>(path: TPath, message: Arrayable$1<string>): void; <TPath extends Path<TInput>>(issues: {}): void; }
Sets the errors for a form path.
setTouched
{ (value: boolean): void; <TPath>(path: TPath, value: boolean): void; }
Sets the touched state of the form. Alternatively, pass a path to set the touched state of a specific form path.
setValue
<TPath>(path: TPath, value: PathValue<TInput, TPath>) => void
Set a form field value by name.
setValues
(values: PartialDeep<TInput>, opts?: SetValueOptions) => void
Set the value for a form field.
submitAttemptsCountThe number of times the form has been submitted, regardless of the form's validity.
validate
() => Promise<FormValidationResult<TOutput>>
Validate the form.
valuesThe current values of the form.
wasSubmittedWhether the form was submitted, which is true if the form was submitted and the submission was successful.