Hook Form React
March 11, 2024 · View on GitHub
This library is a lightweight, dependency-free solution for form validation and submission designed specifically for React applications.
English | 中文 | API | Stackblitz
Developed using React Hooks and TypeScript, it aims to provide a simple, efficient, and extensible way to handle form validation and submission, whether in simple or complex form scenarios. The design philosophy of this library emphasizes compatibility and extensibility, with the principle of supporting developers to achieve the richest functionality with the least code possible. It does not bind to any UI component library, thereby supporting all React component libraries.
Features
- Zero Dependencies: Avoids project bloat and compatibility issues that may arise from external dependencies.
- Highly Extensible: Easily adaptable to various validation rules and form scenarios to meet different requirements.
- TypeScript Support: Takes full advantage of TypeScript's type checking to enhance code readability and maintainability.
- Universality: Compatible with all UI component libraries, providing a unified form processing solution for React developers.
- Documentation Support: Utilizes TypeDoc to generate comprehensive documentation, helping developers better understand and use the features of the library.
- Flexible Packaging Support: Uses Rollup for packaging, supporting UMD, CommonJS, and ES module formats to adapt to different usage scenarios and environments.
Version Notes
-
Future Plans for Next Versions
- Support for object-nested forms.
- Antd Components: Still considering whether to adapt or not (it's still usable without adaptation). Due to the deep coupling of Antd's own Form.Item and Form, and the requirement for basic forms to be nested in Form.Item for standard display effects, adapting might not offer as good a development experience as using Antd's own forms. Still undecided.
- MUI Components: These components do not come with form validation, generally used with react-hook-form (which does not provide a good experience), so there will be adaptations in the future. However, as this component library is not currently used by our company, the priority is not high.
-
v1.0.0 (Official Release)
- Refactored the validation rule implementation class for a friendlier usage experience, and added several common validation rules All common validation rules. The validation rules have not been fully tested; issues are welcome to be reported.
- NextUI Components: All forms have now been adapted All adapted components (any omissions will be updated, @manual dog, hehe)
- Fixed inaccurate type declarations.
- Added test projects for functionality verification.
-
v0.5.x (Core Implementation Preview)
- The core framework has been implemented, offering a smooth user experience, and can be directly used see advanced usage below.
- Overall good extensibility, with component library related code and core form code being completely isolated, laying the foundation for future support of different component libraries.
- Complete control over form data state and form error state, allowing for customization according to business logic.
- Validation rules are also uniformly implemented, making extension and customization convenient.
- Zero dependencies, purely hooks-based.
Component Library Support
-
90 Points: NextUI provides a good experience, and issues are promptly fixed (also in use by ourselves).
-
60 Points: MUI, given its lack of support for form validation, using hook-form-react is still a good choice. At least compared to react-hook-form, it doesn't have a bunch of complex concepts, right?
-
50 Points: Antd components have a good native form experience, prefer to choose their own forms (subsequent adaptations mainly consider dual component library scenarios).
-
50 Points: ......
Installation
# pnpm
pnpm add hook-form-react
# yarn
yarn add hook-form-react
# npm
npm i hook-form-react
Usage
Basic usage
In principle, it can adapt to all React component libraries, although this slightly increases the amount of code.
// Basic usage: In principle, it can adapt to all React component libraries, although this slightly increases the amount of code.
import { useAttr, useFormData } from 'hook-form-react'
// Using NextUI
import { Button, Input, Link } from '@nextui-org/react'
const Example = () => {
const formData = useFormData(
{ password: '', username: '' }, // Default data
{
// Validation rules for password
password: [
{
execute: async (value) => !!value,
msg: 'Password cannot be empty'
}
],
// Validation rules for username
username: [
{
execute: async (value) => !!value,
msg: 'Username cannot be empty'
}
]
}
)
// Submission
const submit = async () => {
// Validate all form fields
const isValid = await formData.doAllValidate()
console.log('submit:isValid: ', isValid)
if (isValid) {
// Validation successful
console.log('formValue:', formData.value)
}
}
return (
<div>
<Input
placeholder="Please enter your username"
className="mb-4 mt-10 login-input text-sm"
isInvalid={formData.errors.username?.isInvalid} // Bind error state
errorMessage={formData.errors.username?.msg} // Bind error message
value={formData.value.username} // Bind value
onChange={(e) => formData.pushValue('username', e.target.value)} // Handle onChange
></Input>
<Input
autoComplete="new-password"
type="password"
placeholder="Please enter your password"
value={formData.value.password}
isInvalid={formData.errors.password?.isInvalid}
errorMessage={formData.errors.password?.msg}
onChange={(e) => formData.pushValue('password', e.target.value)}
></Input>
<Button onClick={submit}>Login</Button>
</div>
)
}
Advanced Usage
Providing Utility Tools for Faster Development Without Losing Customizability
// Advanced Usage: Providing Utility Tools for Faster Development Without Losing Customizability
import { Button, Input } from '@nextui-org/react'
import { useAttr, useFormData, Verifications } from 'hook-form-react'
export const Example = () => {
const formData = useFormData(
{ password: '', username: '' },
{
// Supports multiple validations
password: [
// Built-in validator for required field validation
// Developers can also add other validation rules in their projects, see the developer documentation for details (to be added)
Verifications.required(),
// Built-in validator for password validation
Verifications.password()
],
username: [
// Built-in validator for required field validation + custom message
Verifications.required('Username cannot be empty'),
// Built-in validator for username validation
Verifications.username()
]
}
)
// Use component to quickly bind hooks
const attr = useAttr(formData)
const submit = async () => {
const isValid = await formData.doAllValidate()
console.log('submit:isValid: ', isValid)
if (isValid) {
console.log('formValue', formData.value)
}
}
return (
<div className="p-10 pt-18 pb-0 flex-col">
<Input
placeholder="Please enter your username"
// Comment out the original binding logic
// value={formData.value.username}
// onChange={(e) => formData.pushValue('username', e.target.value)}
// isInvalid={formData.errors.username?.isInvalid}
// errorMessage={formData.errors.username?.msg}
// Replace with quick binding
// NextUI.N_Input is specifically adapted for [NextUI.Input], other components are being supplemented
// Developers can also add support for third-party components in their projects, see the developer documentation for details (to be added)
{...attr('username', attr.NextUI.N_Input)}
></Input>
<Input
autoComplete="new-password"
type="password"
placeholder="Please enter your password"
{...attr('password', attr.NextUI.N_Input)}
// value={formData.value.password}
// isInvalid={formData.errors.password?.isInvalid}
// errorMessage={formData.errors.password?.msg}
// onChange={(e) => formData.pushValue('password', e.target.value)}
></Input>
<Button onClick={submit}>Login</Button>
</div>
)
}
Nested Object Forms
Introducing a new hook useSubFormData for handling nested forms, which, in principle, can handle an arbitrary number of object nesting layers (i.e., infinite nesting).
// useSubFormData
const value10Form = useSubFormData(formData.formData, 'value10', {
haha: [Verifications.required(), Verifications.email()]
})
/**
* This is required for binding to form components of nested objects.
*/
const attrValue10 = useAttr(value10Form)
// Submit
const submit = async () => {
const isValid = await formData.doAllValidate()
// Nested forms need to be validated separately
const isValidValue10 = await value10Form.doAllValidate()
console.log('submit:isValid: ', isValid, isValidValue10)
if (isValid && isValidValue10) {
// The top-level form can access all values
console.log('formValue', formData.value)
}
}
// Reset
const reset = () => {
formData.reset()
// Error states need to be reset separately
value10Form.formErrors.reset()
}
Full Example
API Reference
This section should provide detailed information about the hooks, functions, their parameters, return types, and usage examples offered by the library, enabling developers to quickly get started and effectively utilize the library's features.
Contribution Guidelines
We welcome and encourage community members to contribute to this project, whether through submitting bug reports, feature requests, or directly contributing code. Please refer to our contribution guidelines for more information.
License
This project is licensed under the MIT License, details of which can be found in the LICENSE file.