Type-safe, declarative and performant React form & validation library
npm install @virtuslab/formts




Type-safe, declarative and performant React form & validation library
A stable release has been reached. Further development of new features is
currently not planned. Bug fixes will be provided if needed, feature requests
wil still be considered.
- Fully type-safe API, purpose built to get the most out of Typescript
type-inference
- Declarative definition of form shape and validation rules
- Runtime type-checking of form values against the schema
- Convenient hooks & context based API allowing for isolated re-renders
- Plain react-typescript, 0 dependencies
- View layer agnostic - no components are provided, works with any 3rd-party
components
- handleChange function for dealing with change events automatically
- Advanced validation API which enables:
- specifying dependencies on other fields
- specifying validation triggers for individual rules
- selective validation of just the affected fields on value changes
- separation of error messages from error codes (optional)
- async validation rules with debounce option
- easy mixing of built-in rules with custom functions
- combining multiple validation rules into composite validators
- Good scalability for very large and complex forms
#### 1) Install
``bash`
npm install @virtuslab/formts
#### 2) Define shape of the form
`ts
import { FormSchemaBuilder, FormFields } from "@virtuslab/formts";
const Schema = new FormSchemaBuilder()
.fields({ answer: FormFields.string() })
.errors
.build();
`
#### 3) Define validation rules (optional)
`ts
import { FormValidatorBuilder } from "@virtuslab/formts";
const validator = new FormValidatorBuilder(Schema)
.validate(
Schema.answer,
val => (val === "" ? "Required!" : null),
val => (val !== "42" ? "Wrong answer!" : null)
)
.build();
`
#### 3) Create controller holding form state
`tsx
import { useFormController, FormProvider } from "@virtuslab/formts";
const MyForm: React.FC = () => {
const controller = useFormController({ Schema, validator });
return (
);
};
`
#### 4) Connect inputs to form
`tsx
import { useField } from "@virtuslab/formts";
const AnswerField: React.FC = () => {
const field = useField(Schema.answer);
return (
id={field.id}
value={field.value}
onChange={field.handleChange}
onBlur={field.handleBlur}
/>
{field.error}
);
};
`
#### 5) Connect actions to form
`tsx
import { useFormHandle } from "@virtuslab/formts";
const FormActions: React.FC = () => {
const form = useFormHandle(Schema);
return (
type="submit"
disabled={form.isValid === false}
onClick={() => form.submit(console.log)}
>
Submit!
);
};
`
Currently API documentation is available in form of:
- exhaustive JSDocs
- TYPEDOC docs
- CodeSandbox examples
Play around with the code on _CodeSandbox_ to learn _Formts_ API and features:
a) Step-by-step introduction:
1. basic form (naive)
2. basic form + optimized re-renders
3. basic form + validation
4. basic form + Material-UI
b) HTML input bindings:
1. radio group input
2. checkbox group input
3. select input
4. input array
5. mui multi-select input
6. mui date-picker input
c) Advanced examples:
1. change password form
2. order pizza form
3. form with summary of validation errors
4. registration stepper form
#### Update 2023:
Some of the reasons outlined below are no longer valid as
react-hook-form has
improved since this project started. It offers good type-safety and performance.
If for some reason you are not happy with it however, this library offers
different approach to many aspects of form management and a powerful validation
API - so it may suit your needs better.
#### a) Type-safety
Most popular form libraries like Formik and react-hook-form are written in
Typescript but are not _designed_ with type-safe API as a primary concern.
There is some evidence that this is important for some people:
- Reddit: Fully type-safe form libraries?
- Formik issue: Strongly Typed Fields
- react-hook-form extension: strictly-typed
There are some existing truly type-safe react form solutions, but each has a
costly dependency associated with it:
- formstate --> MobXfp-ts
- Typescript.fun
--> ReasonML
- ReForm -->
#### b) Performance
There are SOME form libraries with really good performance (react-hook-form).
However combining convenient Context based hook API with React performance
optimizations is still problematic. See
https://react-hook-form.com/advanced-usage#FormProviderPerformance for example.
#### c) Declarative validation API
Usually form libs "outsource" advanced validation to schema-based libraries such
as Yup. This seems like a great idea but has some limitations:
- yup and similar packages are not designed with type-safety in mind
- Advanced optimizations (such as validating only the affected fields rather
than the entire form) are not available.
- Form values type is limited by schema definition API and can't represent more
advanced TS types
- Adding required validator does not impact type of values.number | ""
- number() fields are typed as , this is because HTML number inputs""` as empty value.
work with
- Definition of form shape and validation split into 2 separate steps
- Binding to input components is more verbose than with other form libraries
(this is intentional to keep API type-safe and view-layer agnostic)