Skip to content

Latest commit

 

History

History
202 lines (152 loc) · 7.8 KB

README.md

File metadata and controls

202 lines (152 loc) · 7.8 KB

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.