Usetheform is a lightweight, dependency-free React library for composing declarative forms and managing their state. It's simple to use, flexible, and powerful for handling nested fields, validation, and much more.
π Documentation
β‘ Quickstart
π₯ Features
π Recipes
π§ Motivation
π§ͺ Code Sandboxes
π€ How to Contribute
π License
- π¦ Easy integration with libraries like React Select/Material UI and React Dropzone/Material UI Dropzone
- β Sync and Async validation at:
- π Schema validation with:
- 𧬠Follows native HTML standards β see in action
- π§ Reducer support at:
- π§© Easy handling of arrays, objects, and nested structures
- π¦ Tiny bundle size, zero dependencies β Check it on Bundlephobia
Install usetheform
using your preferred package manager:
npm install --save usetheform
yarn add usetheform
import React from "react";
import { Form, Input, useValidation } from "usetheform";
import { ReducerFn, ValidatorFn, OnChangeFormFn, OnSubmitFormFn } from "usetheform/types";
interface MyFormState {
firstname: string;
lastname: string;
age: number;
}
const preventNegativeNumber: ReducerFn<MyFormState["age"]> = (next) =>
next <= 0 ? 0 : next;
const required: ValidatorFn<MyFormState["firstname"]> = (value) =>
value?.trim() ? undefined : "Required";
export default function App() {
const onChange: OnChangeFormFn<MyFormState> = (formState) => console.log("ON_CHANGE:", formState);
const onSubmit: OnSubmitFormFn<MyFormState> = (formState) => console.log("ON_SUBMIT:", formState);
const [status, validation] = useValidation([required]);
return (
<Form<MyFormState> onSubmit={onSubmit} onChange={onChange}>
<Input name="firstname" type="text" touched {...validation} />
{status.error && <span>{status.error}</span>}
<Input name="lastname" type="text" />
<Input name="age" type="number" value={18} reducers={preventNegativeNumber} />
<button type="submit">Submit</button>
</Form>
);
}
interface FormState { counter: number; }
import { createFormStore } from 'usetheform';
const [formStore, useFormSelector] = createFormStore<FormState>({ counter: 0 });
export const awesomeFormStore = formStore;
export const useAwesomeFormSelector = useFormSelector;
import { Form, Input } from 'usetheform';
import { awesomeFormStore } from './awesomeFormStore';
export default function AwesomeForm() {
return (
<>
<Form<FormState> formStore={awesomeFormStore}>
<Input type="number" name="counter" value="0" placeholder="Counter" />
</Form>
<Counter />
</>
);
}
import { useAwesomeFormSelector } from './awesomeFormStore';
export const Counter = () => {
const [counter, setCounterValue] = useAwesomeFormSelector<"counter">((state) => state.counter);
return (
<div>
<span>{counter}</span>
<button onClick={() => setCounterValue(prev => ++prev)}>Increase</button>
<button onClick={() => setCounterValue(prev => --prev)}>Decrease</button>
<button onClick={() => setCounterValue(0)}>Reset</button>
</div>
);
};
Usetheform was created to provide a highly flexible, declarative way to handle forms in React with no dependencies. It supports:
- Nested field structures
- Synchronous & asynchronous validation
- Custom input and reducer logic
- Schema-based validation
- Tiny footprint
If you find this library useful, please β the repo. It means a lot! π
- Antonio Pangallo β @antonio_pangall
- Twitter-style Form Bar
- Shopping Cart
- Form Examples (Select, Slider, Collections)
- Various Implementations
- Wizard
- FormContext
- Material UI + React Select
- Validation (Yup, Zod, Joi, Superstruct)
- React Dropzone + Material UI
π Thanks for considering contributing! Please read our CONTRIBUTING.md for guidelines.
This project is licensed under the MIT License. See the LICENSE file for details.