Skip to content

React library for composing declarative forms, manage their state, handling their validation and much more.

License

Notifications You must be signed in to change notification settings

iusehooks/usetheform

Repository files navigation

Usetheform Logo

An easy way to build forms in React.

Code Coverage Usetheform CI Bundle Size Tweet


Demo GIF

πŸ’‘ What is Usetheform?

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

πŸ”₯ Features

⚑ Quickstart

Install usetheform using your preferred package manager:

npm install --save usetheform
yarn add usetheform

Basic usage example:

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>
  );
}

πŸ“– Recipes

Accessing form fields outside the Form context

🧱 Step 1: Create a form store

interface FormState { counter: number; }
import { createFormStore } from 'usetheform';

const [formStore, useFormSelector] = createFormStore<FormState>({ counter: 0 });

export const awesomeFormStore = formStore;
export const useAwesomeFormSelector = useFormSelector;

🧩 Step 2: Create your awesome form

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 />
    </>
  );
}

πŸ”Œ Step 3: Connect your components

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>
  );
};

🧠 Motivation

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! πŸ™

πŸ‘€ Author

⭐ Stargazers

Stargazers repo roster

Code Sandboxes

How to Contribute

πŸŽ‰ Thanks for considering contributing! Please read our CONTRIBUTING.md for guidelines.

πŸ“„ License

This project is licensed under the MIT License. See the LICENSE file for details.