https://github.com/tkrotoff/react-form-with-constraints
Simple form validation for React
https://github.com/tkrotoff/react-form-with-constraints
constraints form form-validation html5 input-validation react validation
Last synced: 8 months ago
JSON representation
Simple form validation for React
- Host: GitHub
- URL: https://github.com/tkrotoff/react-form-with-constraints
- Owner: tkrotoff
- License: mit
- Created: 2017-05-16T14:43:00.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2023-01-27T13:55:49.000Z (about 3 years ago)
- Last Synced: 2025-06-15T18:59:34.580Z (8 months ago)
- Topics: constraints, form, form-validation, html5, input-validation, react, validation
- Language: TypeScript
- Homepage:
- Size: 4.82 MB
- Stars: 126
- Watchers: 9
- Forks: 20
- Open Issues: 21
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# react-form-with-constraints
[](https://badge.fury.io/js/react-form-with-constraints)
[](https://github.com/tkrotoff/react-form-with-constraints/actions)
[](https://codecov.io/gh/tkrotoff/react-form-with-constraints)
[](https://bundlephobia.com/result?p=react-form-with-constraints@latest)
[](https://github.com/prettier/prettier)
[](https://github.com/airbnb/javascript)
Simple form validation for React
- Installation: `npm install react-form-with-constraints`
- CDN: https://unpkg.com/react-form-with-constraints/dist/
Check the [changelog](CHANGELOG.md) for breaking changes and fixes between releases.
## Introduction: what is HTML5 form validation?
⚠️ [Client side validation is cosmetic, you should not rely on it to enforce security](https://stackoverflow.com/q/162159)
```HTML
Email:
Submit
```


The `required` HTML5 attribute specifies that the user must fill in a value, [`type="email"`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/email) checks that the entered text looks like an email address.
Resources:
- [Making Forms Fabulous with HTML5](https://web.archive.org/web/20220317195146/https://www.html5rocks.com/en/tutorials/forms/html5forms/)
- [Constraint Validation: Native Client Side Validation for Web Forms](https://web.archive.org/web/20210818094708/https://www.html5rocks.com/en/tutorials/forms/constraintvalidation/)
- [web.dev - Learn Forms](https://web.dev/learn/forms/)
- [MDN - Form data validation](https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Form_validation)
- [MDN - Form input types](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#Form__types)
- [UX Research Articles - Usability Testing of Inline Form Validation](https://baymard.com/blog/inline-form-validation)
## What react-form-with-constraints brings
- Minimal API and footprint
- Unobtrusive: easy to adapt regular [React code](https://reactjs.org/docs/forms.html)
- HTML5 error messages personalization: `My custom error message`
- Custom constraints: ` ...}>`
- Warnings and infos: ``, ``
- Async validation
- No dependency beside React (no Redux, MobX...)
- Re-render only what's necessary
- Easily extendable
- [Bootstrap](examples/Bootstrap) styling with npm package `react-form-with-constraints-bootstrap`
- [Material-UI](examples/MaterialUI) integration with npm package `react-form-with-constraints-material-ui`
- Support for [React Native](examples/ReactNative) with npm package `react-form-with-constraints-native`
- ...
```JSX
Should be at least 5 characters long
!/\d/.test(value)} warning>
Should contain numbers
!/[a-z]/.test(value)} warning>
Should contain small letters
!/[A-Z]/.test(value)} warning>
Should contain capital letters
```
## Examples
- CodePen basic Password example: https://codepen.io/tkrotoff/pen/BRGdqL ([StackBlitz version](https://stackblitz.com/github/tkrotoff/react-form-with-constraints/tree/master/examples/Password))

- [Bootstrap example (React hooks)](https://stackblitz.com/github/tkrotoff/react-form-with-constraints/tree/master/examples/Bootstrap)
- [Material-UI example (React hooks)](https://stackblitz.com/github/tkrotoff/react-form-with-constraints/tree/master/examples/MaterialUI)
- [WizardForm example (React hooks)](https://stackblitz.com/github/tkrotoff/react-form-with-constraints/tree/master/examples/WizardForm)
- [SignUp example (React classes)](https://stackblitz.com/github/tkrotoff/react-form-with-constraints/tree/master/examples/SignUp)
- [ClubMembers example (React classes + MobX)](https://stackblitz.com/github/tkrotoff/react-form-with-constraints/tree/master/examples/ClubMembers)
- [Password without state example (React hooks)](https://stackblitz.com/github/tkrotoff/react-form-with-constraints/tree/master/examples/PasswordWithoutState)
- [Server-side rendering example (React hooks)](https://stackblitz.com/github/tkrotoff/react-form-with-constraints/tree/master/examples/ServerSideRendering)
- [React Native example (React classes)](examples/ReactNative):
| iOS | Android |
| ----------------------------------------------------- | ------------------------------------------------------------- |
|  |  |
- Other examples from [the examples directory](examples):
- [Plain old React form validation example (React hooks)](https://stackblitz.com/github/tkrotoff/react-form-with-constraints/tree/master/examples/PlainOldReact)
- [React with HTML5 constraint validation API example (React hooks)](https://stackblitz.com/github/tkrotoff/react-form-with-constraints/tree/master/examples/HTML5ConstraintValidationAPI)
## How it works
The API works the same way as [React Router](https://reacttraining.com/react-router/web/example/basic):
```JSX
```
It is also inspired by [AngularJS ngMessages](https://docs.angularjs.org/api/ngMessages#usage).
If you had to implement validation yourself, you would end up with [a global object that tracks errors for each field](examples/PlainOldReact/App.tsx).
react-form-with-constraints [works similarly](packages/react-form-with-constraints/src/FieldsStore.ts).
It uses [React context](https://reactjs.org/docs/legacy-context.html) to share the [`FieldsStore`](packages/react-form-with-constraints/src/FieldsStore.ts) object across [`FieldFeedbacks`](packages/react-form-with-constraints/src/FieldFeedbacks.tsx) and [`FieldFeedback`](packages/react-form-with-constraints/src/FieldFeedback.tsx).
## API
The API reads like this: "for field when constraint violation display feedback", example:
```JSX
Should be at least 5 characters long
```
```
for field "password"
when constraint violation "valueMissing" display
when constraint violation "patternMismatch" display "Should be at least 5 characters long"
```
(\*) [element.validationMessage](https://www.w3.org/TR/html51/sec-forms.html#the-constraint-validation-api)
Async support works as follow:
```JSX
available ?
Username available :
Username already taken, choose another
// Why key=*? Needed otherwise React gets buggy when the user rapidly changes the field
}
/>
```
Trigger validation:
```JSX
function MyForm() {
const form = useRef(null);
async function handleChange({ target }) {
// Validates only the given fields and returns Promise
await form.current.validateFields(target);
}
async function handleSubmit(e) {
e.preventDefault();
// Validates the non-dirty fields and returns Promise
await form.current.validateForm();
if (form.current.isValid()) console.log('The form is valid');
else console.log('The form is invalid');
}
return (
Too short
available ?
Username available :
Username already taken, choose another
}
/>
);
}
```
**Important note:**
If a field (i.e an ``) does not have a matching `FieldFeedbacks`, the library won't known about this field (and thus won't perform validation).
The field name should match `FieldFeedbacks.for`:
```JSX
...
```
- [`FieldFeedbacks`](packages/react-form-with-constraints/src/FieldFeedbacks.tsx)
- `for: string` => reference to a `name` attribute (e.g ``), should be unique to the current form
- `stop?: 'first' | 'first-error' | 'first-warning' | 'first-info' | 'no'` =>
when to stop rendering `FieldFeedback`s, by default stops at the first error encountered (`FieldFeedback`s order matters)
Note: you can place `FieldFeedbacks` anywhere, have as many as you want for the same `field`, nest them, mix them with `FieldFeedback`... Example:
```JSX
...
...
```
- [`FieldFeedback`](packages/react-form-with-constraints/src/FieldFeedback.tsx)
- `when?`:
- [`ValidityState`](https://developer.mozilla.org/en-US/docs/Web/API/ValidityState) as a string => HTML5 constraint violation name
- `'*'` => matches any HTML5 constraint violation
- `'valid'` => displays the feedback only if the field is valid
- `(value: string) => boolean` => custom constraint
- `error?: boolean` => treats the feedback as an error (default)
- `warning?: boolean` => treats the feedback as a warning
- `info?: boolean` => treats the feedback as an info
- `children` => what to display when the constraint matches; if missing, displays the [HTML5 error message](https://www.w3.org/TR/html51/sec-forms.html#the-constraint-validation-api) if any
- [`Async`](packages/react-form-with-constraints/src/Async.tsx) => Async version of `FieldFeedback` (similar API as [react-promise](https://github.com/capaj/react-promise))
- `promise: (value: string) => Promise` => a promise you want to wait for
- `pending?: React.ReactNode` => runs when promise is pending
- `then?: (value: T) => React.ReactNode` => runs when promise is resolved
- `catch?: (reason: any) => React.ReactNode` => runs when promise is rejected
- [`FormWithConstraints`](packages/react-form-with-constraints/src/FormWithConstraints.tsx)
- `validateFields(...inputsOrNames: Array): Promise` =>
Should be called when a `field` changes, will re-render the proper `FieldFeedback`s (and update the internal `FieldsStore`).
Without arguments, all fields (`$('[name]')`) are validated.
- `validateFieldsWithoutFeedback(...inputsOrNames: Array): Promise` =>
Validates only all non-dirty fields (won't re-validate fields that have been already validated with `validateFields()`),
If you want to force re-validate all fields, use `validateFields()`.
Might be renamed to `validateNonDirtyFieldsOnly()` or `validateFieldsNotDirtyOnly()` in the future?
- `validateForm(): Promise` =>
Same as `validateFieldsWithoutFeedback()` without arguments, typically called before to submit the `form`.
Might be removed in the future?
- `isValid(): boolean` => should be called after `validateFields()`, `validateFieldsWithoutFeedback()` or `validateForm()`, indicates if the fields are valid
- `hasFeedbacks(): boolean` => indicates if any of the fields have any kind of feedback
- `resetFields(...inputsOrNames: Array): Field[]` =>
Resets the given fields and re-render the proper `FieldFeedback`s.
Without arguments, all fields (`$('[name]')`) are reset.
- [`Field`](packages/react-form-with-constraints/src/Field.ts) =>
```TypeScript
{
name: string;
validations: { // FieldFeedbackValidation[]
key: number;
type: 'error' | 'warning' | 'info' | 'whenValid';
show: boolean | undefined;
}[];
isValid: () => boolean
}
```
- [`Input`](packages/react-form-with-constraints/src/Input.tsx)
If you want to style ``, use `` instead: it will add classes `is-pending`, `has-errors`, `has-warnings`, `has-infos` and/or `is-valid` on `` when the field is validated.
Example: `` can generate ``
FYI `react-form-with-constraints-bootstrap` and `react-form-with-constraints-material-ui` already style the fields to match their respective frameworks.
## Browser support
react-form-with-constraints needs [`ValidityState`](https://developer.mozilla.org/en-US/docs/Web/API/ValidityState) which is supported by all modern browsers and IE 11.
It also needs a polyfill such as [core-js](https://github.com/zloirock/core-js) to support IE 11, see [React JavaScript Environment Requirements](https://reactjs.org/docs/javascript-environment-requirements.html).
You can use HTML5 attributes like `type="email"`, `required`, [`minlength`](https://caniuse.com/#feat=input-minlength)...
```JSX
Email
```
...and/or rely on `when` functions:
```JSX
Email
value.length === 0}>Please fill out this field.
!/\S+@\S+/.test(value)}>Invalid email address.
```
In the last case you will have to manage translations yourself (see SignUp example).
## Notes
- A [`type="hidden"`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/hidden#Validation), [`readonly`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-readonly) or [`disabled`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-disabled) input won't trigger any HTML5 form constraint validation like [`required`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-required), see https://codepen.io/tkrotoff/pen/gdjVNv