A type-safe approach to managing complex form state in React.
This library provides integration with @stackup/validate to handle validation. However, it should be pretty easy to integrate whatever validation library you prefer.
You should also checkout @stackup/inputs, which includes some ready-made form fields.
import React from "react";
import { useForm, useField, useNoValidate } from "@stackup/form";
const Form = () => {
const form = useForm({ initialValue: { email: "", name: "" } });
const validate = useValidation(form, value => {
if (value.email) {
return { valid: true, value };
} else {
return { valid: false, error: { email: "is required" } };
}
});
const submit = useSubmit(validate, value => {
console.log(value);
});
return (
<form onSubmit={submit}>
<Input type="email" label="Email" field={useField(form, "email")} />
<Input type="text" label="Name" field={useField(form, "name")} />
<button type="submit">Save</button>
</form>
);
};
const Input = ({
label,
field: { id, value, error, touched, setValue, setTouched },
...props
}) => (
<div>
<label htmlFor={id}>{label}</label>
<input
{...props}
id={id}
value={value}
onBlur={useCallback(() => setTouched(true), [])}
onChange={useCallback(e => setValue(e.target.value), [setValue])}
/>
{touched && error && <p>{error}</p>}
</div>
);
- useForm
- useField
- useValidation
- useValidate
- useSubmit
- useFieldItem
- usePushItem
- useInsertItem
- useRemoveItem
- useIdentifier
- Form
- FormField
- ValidateFn
- Submit
- UseFormOptions
- UseValidationOptions
Create a new form. A form requires an initial value, a function to validate, and a submit handler.
A form behaves just like any other field, but with some extra properties for managing submission.
The initial value for the form can be literally anything! Usually, it's an object, but it could be any type of value.
The useForm
function takes two generic parameters. The first describes the
shape of your form state. The second is optional, but it describes the result
of casting your form state with a validator. The casted value is what will be
passed to submit
.
If your form doesn't require validation, see useNoValidate.
options
UseFormOptions<Value>
Form values can be primitive
const form = useForm({ initialValue: "" });
But usually, they'll contain an object
const form = useForm({
initialValue: {
email: "",
name: ""
}
});
Returns Form<Value>
Create a field for a given property.
const form = useForm({
initialValue: {
email: "",
profile: { name: "" } }
}
});
const email = useField(form, "email");
const profile = useField(form, "profile");
const name = useField(profile, "name");
Returns FormField<any>
Use a plain ol' function for validation.
This hook can also be used to incorporate your favorite validation library.
form
Form<Value, Value>fn
ValidateFn<Value, Result>opts
UseValidationOptions (optional, default{}
)
const validation = useValidation(form, value => {
if (!value.email) {
return { valid: false, error: { email: "can't be blank" } };
}
return { valid: true, value };
});
Returns Form<Value, Result>
Add validation to the form using @stackup/validate.
form
Form<Value, Value>validator
Validator<Value, Result>opts
UseValidationOptions?
const validator = schema({
email: assert(isString).then(refute(isBlank))
});
const validate = useValidate(form, validator);
Returns Form<Value, Result>
Create a submit handler for the form.
form
Form<Value, Result>fn
SubmitFn<Result>
Sumbitting a form
const form = useForm({ initialValue: "foo" });
const submit = useSubmit(form, console.log);
Sumbitting with validation
const form = useForm({ initialValue: "foo" });
const validate = useValidate(form, myValidator);
const submit = useSubmit(validate, console.log);
Returns Submit
Create a field for a specific index in an array.
This hook is intended for use in building forms with "Add another" functionality.
const form = useForm({ initialValue: { pets: [{ name: "" }] } });
const pets = useField(form, "pets");
const pet = useFieldItem(pets, 0);
const name = useField(pet, "name");
Returns FormField<Value>
Adds a new value to the end to an array of values.
This can be used to create a form with repeating fields.
const pets = useField(form, "pets");
const pet = useFieldItem(pets, 0);
const addPet = usePushItem(pets, { name: "" });
Adds a new value at a specific position to an array of values.
This can be used to create a form with repeating fields.
const pets = useField(form, "pets");
const pet = useFieldItem(pets, 0);
const insert = useInsertItem(pets, 0, { name: "" });
Removes a value at the given index from array of values.
This can be used to create a form with repeating fields.
const pets = useField(form, "pets");
const pet = useFieldItem(pets, 0);
const removePet = useRemoveItem(pets, 0);
Creates a unique identifier that will remain consistent across re-renders.
This hook does not currently support SSR.
id
string?
Returns string
Extends FormField<Value>
The value returned by useForm
.
The initial values for the form.
Type: Value
The initial errors on the fields.
Type: FormError<Value>
The initially touched fields.
Type: FormTouched<Value>
Indicate that the form is validating
Type: SetState<boolean>
Indicate that the form is validating
Type: SetState<boolean>
Run validation
Type: function (opts: ValidateOptions): Promise<ValidationResult<Value, Result>>
The primary form data structure.
A unique ID for this form field. This can be used to associate fields with a label.
Type: string
The name or array index that was given to useField or useFieldItem.
The current value of the field.
Type: Value
An error or errors that are associated with this field or it's children.
Type: FormError<Value>
Indicates that this field or it's children have been modified by the user.
Type: FormTouched<Value>
Indicates that validation is currently being run
Type: boolean
Indicates that the form is currently being submitted
Type: boolean
Change the value. Just like with setState
, you can pass a callback
to this function to get the current value and update it.
Type: SetState<Value>
Update the error.
Type: SetState<FormError<Value>>
Indicate that this field has been touched. This is usually called in onBlur
.
Type: SetState<FormTouched<Value>>
A function used for validation. This function must indicate whether or not the form is valid.
The error
property can be used to set errors on the form.
The value
property can be used to transform the form's values before
validation.
Type: function (value: Value): (ValidationResult<Value, Result> | PromiseLike<ValidationResult<Value, Result>>)
Submits the form.
Type: function (event: FormEvent<HTMLFormElement>): Promise<void>
The options that can be passed to useForm.
Customize the base ID for all fields.
Type: string
The initial values for the form.
Type: Value
The initial errors on the fields.
Type: FormError<Value>
The initially touched fields.
Type: FormTouched<Value>
Configures when validation runs.
Enables validation whenever values change.
Type: boolean
Enables validation whenever a field is touched.
Type: boolean