Lightweight form library focused on ease of use. This library was inspired by antd
form component and react-hook-form
.
- Small size
- Type-friendly, all components and hooks fully typed
- Ease to use, you need only
createForm
method to get all the functionality - Build in promise based validation, you can easy use your own promise function to validate fields
- No extra re-renders
useWatch
,useField
,useArrayField
,useFieldErrors
hooks- Access to form state in any place of application, even outside of form component
Docs and examples - https://react-any-shape-form.vercel.app/
Install:
npm i react-any-shape-form
Use it like this:
import { createForm } from 'react-any-shape-form';
const MyForm = createForm({
name: 'Rina',
age: 24,
})
const MyComponent = () =>
<MyForm onFinish={(state) => {
alert(JSON.stringify(state, undefined, 2));
}}>
<MyForm.Item
name="name"
label="Name"
onChange={value => value}
rules={[
{
required: true,
message: 'Name is required',
validateTrigger: ['onFinish']
},
]}
>
{({ value, onChange }) =>
<input value={value} onChange={e => onChange(e.target.value)} />
}
</MyForm.Item>
<MyForm.Item name="age">
{({ value, onChange }) =>
<input type="number" value={value} onChange={(e) => onChange(+e.target.value)} />
}
</MyForm.Item>
<button type="submit">
Submit button
</button>
</MyForm>
You can find more examples in docs
Field | Type | Description | Default |
---|---|---|---|
initialState | Object |
Predefined fields value | {} |
CSSPrefix | string |
Prefix for css classes | 'form' |
id | string |
html form id | undefined |
children | ReactNode |
Field | Type | Description | Default |
---|---|---|---|
children | FC or ReactElement |
Function/component with value , onChange props |
{} |
label | ReactNode |
Field label | |
rules | ValidationRule[] |
Validation rule | |
onChange | (value: Value, event?: unknown) => any |
Triggers on field state changes | |
onInvalid | (errors: ValidationError[], value: Value) => void |
Triggers on validation error | |
renderLabel | (value: Value, formItemId?: string) => ReactElement |
Customize label | |
renderError | (error: ValidationError<Value>) => ReactElement |
Customize error |
No CSS by default. You need to style form by you own.
You can change classes prefix (.form
by default) using CSSPrefix
property.
You can use renderLabel
to customize <label>
and renderError
for customize form error message.
CSS classes:
.form
- <form>
tag class.
.form__form-item
- form item wrapper
.form__form-item__label
- form item label (<label>
tag)
.form__form-item__error
- form item error
Look at ./storybook/styles.css
as example.
You can pass array of validation rules to Form.Item
.
Don't forget to set error message or return Promise.reject('your-error-message')
.
You can control validation trigger using validationTrigger
:
["onChange"]
- trigger fires if value changed (debounced by 300ms
)
["onFinish"]
- trigger fires only after form submit
[
{
// throw an error if field value is undefined
required: true,
message: "Age is required",
},
{
// if value < 18
min: 18,
type: "number",
message: "some message",
},
{
// if String().length > 100
max: 100,
type: "string",
message: "some error",
},
{
// if myPattern.test() === false
type: "regexp",
pattern: myPattern,
},
{
// If value is not an email address
type: "email",
},
{
// if myValidator function throw an error or return Promise.reject
validator: myValidator,
message: "some error",
},
];
Form.useWatch
- get actual field value
const MyForm = createForm({
name: 'Rina',
age: 24,
})
const SomeComponent = () => {
const name = MyForm.useWatch('name');
...
}
Form.useField
- get control over field state
const [name, setName] = MyForm.useField('name');
Form.useFieldErrors
- get actual field validation errors and validation status
const { errors, status } = MyForm.useFieldErrors('name');
Form.useArrayField
- get control over array field
const MyForm = createForm({
userIds: [] as string[]
})
const SomeComponent = () => {
const { fields, append, delete } = MyForm.useArrayField('userIds');
return (
<>
{fields.map((field, index) =>
<div key={index}>
<input value={field} onChange={e => update(index, e.target.value)} />
<button type="button" onClick={() => remove(index)}>Remove</button>
</div>
)}
<button type="button" onClick={() => append("")}>
Add
</button>
</>
)
}