FormApi
The FormApi
object is the main way to interact with RVF.
It's returned by useForm
and can be scoped to a specific part of the form.
Prop getters
getFormProps
You should call this in every form you have and pass the result to your form element.
const form = useForm({
// ...
});
return (
<form {...form.getFormProps()}>
<YourFormElements />
</form>
);
getInputProps
Returns props that can be spread onto native form controls or thin wrappers around them. It's generally recommended to use this with native form controls. And pass any other props through this helper.
It's important that the component you spread the props into accepts the ref
prop.
This allows RVF to set the value of the field when setValue is called, and is used
to focus the field when it has an error.
<input
{...form.getInputProps("myField", { type: "number" })}
/>
getControlProps
Returns props that can be spread into controlled components to use as a field.
It's important to pass the provided ref
to a focusable HTML element.
This allows the field to be focused when it has an error and also disables RVF's default
behavior of automatically listening to changes in the field.
getHiddenInputProps
Returns props that can be spread into a native form control to use as a hidden field.
This is useful in combination with getControlProps
.
Fields and arrays
field
Returns a FieldApi
object for the specified field.
Can be called without a field name to get an field api currently in-scope form data.
array
Returns a FieldArrayApi
object for the specified field.
Can be called without a field name to get an array api currently in-scope form data.
State accessors
These functions can all be used to access the current state of the form during the render phase.
Even though these are functions, they're still tied to the
render phase. Calling one of these functions in an event
handler or a useEffect
may not return the latest state.
For those use-cases, you should use the
transient api.
name
Returns the name of the specified field. Can be called without a field name to get the name of the field currently in-scope form data.
This can be useful if you want a typesafe way of getting the name of a field, especially if you're scoping.
value
Can be called with the name of a field to get the value of that field.
If the FormApi
is scoped to a specific part of the form,
the field name is relative to the scope.
Can also be called with no arguments to get the entire form data.
If the FormApi
is scoped to a specific part of the form,
this will be limited to the scope.
error
Returns the error message for the specified field, if there is one.
If the FormApi
is scoped to a specific part of the form,
the field name is relative to the scope.
Can also be called with no arguments to get the error for the field currently in scope.
RVF takes the opinion that errors that won't be visible to a user aren't made available through this API. So you don't need to do any additional logic to determine if an error should be displayed to the user beyond checking if there's an error.
defaultValue
Returns the default value for the specified field.
If the FormApi
is scoped to a specific part of the form,
the field name is relative to the scope.
Can also be called with no arguments to get the default value for the currently in-scope form data.
touched
Can be called with the name of a field to get whether or not that field has been touched. If the name of the field is omitted, it will return whether or not the currently scoped field has been touched.
A field has been "touched" after the user has interacted with it and moved on to another field in the form.
dirty
Can be called with the name of a field to get whether or not that field has been changed. If the name of the field is omitted, it will return whether or not the currently scoped field has been dirty.
A field "dirty" when it no longer matches the default value. If the user changes the value back to the default, the field will no longer be dirty.
Fields added dynamically in a field array, will always be dirty after the first change.
formOptions
An object that exposes a couple of the options you passed to useForm
.
action
formId
If you didn't pass a formId
, it will have a default value.
formState
Exposes some form-level state.
The data in here is always based on the root-level form, even
if the FormApi
is scoped to a specific part of the form.
Submit status
These three props tell you about the current state of submission:
isSubmitting
- Whether or not the form is currently submitting.
hasBeenSubmitted
- Whether or not a submit has been attempted.
submitStatus
- "idle" | "submitting" | "error" | "success"
Root-level valid/dirty/touched
These tell you if any field in the form is valid, dirty, or touched.
isValid
isDirty
isTouched
All valid/dirty/touched data
Contains all the valid/dirty/touched data for every field in the form.
touchedFields
dirtyFields
fieldErrors
Transient state accessors
transient
The transient
object contains many of the same state accessors mentioned above,
except that these will not trigger rerenders and will always return the latest state.
This is useful for things like event handlers.
the included state accessors are:
value
defaultValue
touched
dirty
error
formState
Example:
<button
type="button"
// Always logs the latest value of `myField` without causing rerenders
onClick={() =>
console.log(form.transient.value("myField"))
}
>
Log value
</button>
State setters
setValue
Sets the value of the field with the specified name.
This works for both controlled and uncontrolled fields.
For uncontrolled fields, this will manually set the value of the form control using the ref
returned by getInputProps
.
Can also be called without a field name, to set the value of the entire form.
If the FormApi
is scoped to a specific part of the form,
this will be limited to the scope.
clearError
Clears the error message for the specified field. Can be called without a field name to clear the error message for the field in scope.
setTouched
Manually set the touched
state of the specified field.
Can be called without a field name to set the touched state of the field in scope.
setDirty
Manually set the dirty
state of the specified field.
Can be called without a field name to set the dirty state of the field in scope.
focus
Focus the field with the specified name.
This only works if the ref
provided by getInputProps
or getControlProp
was passed to a focusable element.
validate
Manually validates the form. You usually don't need to do this.
resetForm
Resets the form to its initial state. All fields will be reset to their initial values. All touched, dirty, and validation errors will be reset. Optionally, you can provide new initial values to reset.
This will work on the root-level form, even if the FormApi
is scoped to a specific part of the form.
resetField
Resets the field with the specified name to its initial value.
This also resets any touched, dirty, or validation errors for the field.
This works for both controlled and uncontrolled fields.
For uncontrolled fields, this will manually set the value of the form control using the ref
returned by field
.
Optionally, you can pass a default value to reset to.
This will reset cause form.defaultValue('myField')
to return the new default value,
and for form.dirty('myField')
to return use this new default for comparison.
Calling resetForm
or calling resetField
on a parent field, will undo any default value changes made by resetField
.
Can also be called without a field name, to reset the currently in-scope field.
Edge cases with nested fields
Let's say you have a form with default values that look like this:
const form = useForm({
defaultValues: {
name: "John",
address: {
street: "123 Main St",
city: "Anytown",
},
},
});
If you call form.resetField("address.street", "234 Another St")
,
then form.defaultValue("address.street")
will now return "234 Another St"
.
BUT calling form.defaultValue("address")
will return the original street,
{ street: "123 Main St", city: "Anytown" }
. Likewise, calling form.defaultValue
will return the original default values of the entire form.
If you then call form.resetField("address")
, then form.defaultValue("address.street")
will once again return "123 Main St"
.
It works this way to facilitate writing your own sub-form or field components without
having to worry about the implementation details of those in your forms. In this example,
you might have a StreetInput
with location autocomplete, and that component might want to use
resetField
for some of its logic. Now you can do that, and use resetForm
in your form
without having to think about whether or not StreetInput
has called resetField
itself.
scope
Scopes the FormApi
to a specific part of the form.
See the docs on scoping for more details.
renderFormIdInput
Renders a hidden input that sets passes the form id to your server. This is only useful if you're supporting users who don't have JS enabled and you're returning validation errors from your server.
subscribe
Helpers to subscribe to changes transiently (without causing re-renders). These should be used in an effect.
value
Subscribes to any change in the values of the form. Can optionally pass the name of a field to subscribe to that specific field. Returns a function that can be called to unsubscribe.
Example:
useEffect(
() =>
form.subscribe.value((formData) => {
console.log(formData);
}),
[],
);
useEffect(
() =>
form.subscribe.value("myField", (myFieldData) => {
console.log(myFieldData);
}),
[],
);