@zodactive-form/react
v0.0.3
Published
React wrapper for @zodactive-form/core
Downloads
1
Readme
Zodactive Form aims to provide a very simple form reactivity based on the Zod validation library. This package wraps @zodactive-form/core to work with React's reactivity.
Preface
This is not an official Zod library. This is a personal project which is mainly meant to be used by my other projects. However, you are free to use it if you find it useful.
In addition, this library is under development and not all functionality from zod is supported yet.
Description
This React library is a wrapper on top of @zodactive-form/core and provides a reactive store to work forms validated with Zod.
There are 2 exported symbols in @zodactive-form/react:
createFormStore
: This hooks up @zodactive-form/core and creates a simple store which is compatible with React'suseSyncExternalStore
;useForm
: This hook will automatically create a new store and return the result of callinguseSyncExternalStore
. The values are ready to be used in react.
Dependencies
@zodactive-form/react has the following dependencies:
- Zod: The validation library used by @zodactive-form/core;
- React: The reactive ui framework which this package wraps around;
- @zodactive-form/core: Contains the main form validation logic;
Installation
As a simple npm package, it can be installed using your favorite package manager:
npm install @zodactive-form/react
Usage
First, create a Zod schema. Then, pass it to useForm()
to create a reactive store. This store
provides different functions to interact with the reactive form.
import {z} from 'zod';
import {useForm} from '@zodactive-form/react';
const userSchema = z.object({
username: z.string().min(3),
password: z.string().min(3),
confirmPassword: z.string().min(3),
}).refine(
({password, confirmPassword}) => password === confirmPassword,
"Passwords do not match!",
);
export const RegisterForm = () => {
const {
assign,
form,
formErrors,
validate,
valid,
toJson
} = useForm(userSchema);
const updateField = (path: string) => (event: Event) => {
const target = event.target as HTMLInputElement;
assign(path, target.value);
}
const onSubmit = (ev: Event) => {
ev.preventDefault();
if (validate()) {
const formData = toJson();
// Form is valid and data is in the above variable!
}
};
return (
<form onSubmit={onSubmit}>
<label>
<span>Username:</span>
<input type="text"
value={form.username.value}
className={form.username.error ? 'error' : ''}
onInput={updateField('username')}/>
{form.username.error && <span>{form.username.error}</span>}
</label>
<label>
<span>Password:</span>
<input type="password"
value={form.password.value}
className={form.password.error ? 'error' : ''}
onInput={updateField('password')}/>
{form.password.error && <span>{form.password.error}</span>}
</label>
<label>
<span>Confirm Password:</span>
<input type="password"
value={form.confirmPassword.value}
className={form.confirmPassword.error ? 'error' : ''}
onInput={updateField('confirmPassword')}/>
{form.confirmPassword.error && <span>{form.confirmPassword.error}</span>}
</label>
{!!formErrors.length &&
<ul>
{formErrors.map(err => <li>{err}</li>)}
</ul>
}
<button type="submit">Register</button>
</form>
);
}
In the above piece of code, the following is happening:
- A zod schema is created, called
userSchema
; - All fields are strings, with a minimum of 3 characters;
- A special refinement is added to make sure
password
andconfirmPassword
match; - In the component, the store is created using
useStore
; - To make it easy to update components, an input event helper is created:
updateField
; - The final goal of the form is added: the
onSubmit
handler; - The HTML contains 3 fields, each having the following properties:
- value is bound to the
form.<field>.value
property of the store; - A class is dynamically set based on if
form.<field>.error
is set or not; - To update the store, the helper
updateField
is bound to theonInput
event; - Finally, if there is an error message, a span is conditionally rendered;
- value is bound to the
- When an error does not belong to a field, it is stored in
formErrors
, so they are looped at the end of the form (ex: password matching error);
As you can see, it was fairly simple to create a form with full reactive validation based on a Zod schema.
Additional Details
form
contains a structure where each Zod field is split into its value and an error message. Whileform
itself is reactive, the values inside of it are not. To update the form, make sure to callassign
so the store is properly updated;- The form is validated once when it is created, but without adding error messages. This allows the
valid
field to properly be set according to the provided initial data; - When calling
validate()
, all errors are removed. If errors need to be removed at a different time, you can useclearErrors()
;