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.