1.0.1 • Published 10 months ago

@virtuslab/formts v1.0.1

Weekly downloads
1
License
MIT
Repository
github
Last release
10 months ago

build status GitHub license npm npm bundle size examples

Formts

Type-safe, declarative and performant React form & validation library

Status

A stable release has been reached. Further development of new features is currently not planned. Bug fixes will be provided if needed, feature requests wil still be considered.

Features

  • Fully type-safe API, purpose built to get the most out of Typescript type-inference
  • Declarative definition of form shape and validation rules
  • Runtime type-checking of form values against the schema
  • Convenient hooks & context based API allowing for isolated re-renders
  • Plain react-typescript, 0 dependencies
  • View layer agnostic - no components are provided, works with any 3rd-party components
  • handleChange function for dealing with change events automatically
  • Advanced validation API which enables:
    • specifying dependencies on other fields
    • specifying validation triggers for individual rules
    • selective validation of just the affected fields on value changes
    • separation of error messages from error codes (optional)
    • async validation rules with debounce option
    • easy mixing of built-in rules with custom functions
    • combining multiple validation rules into composite validators
  • Good scalability for very large and complex forms

Getting Started

1) Install

npm install @virtuslab/formts

2) Define shape of the form

import { FormSchemaBuilder, FormFields } from "@virtuslab/formts";

const Schema = new FormSchemaBuilder()
  .fields({ answer: FormFields.string() })
  .errors<string>()
  .build();

3) Define validation rules (optional)

import { FormValidatorBuilder } from "@virtuslab/formts";

const validator = new FormValidatorBuilder(Schema)
  .validate(
    Schema.answer,
    val => (val === "" ? "Required!" : null),
    val => (val !== "42" ? "Wrong answer!" : null)
  )
  .build();

3) Create controller holding form state

import { useFormController, FormProvider } from "@virtuslab/formts";

const MyForm: React.FC = () => {
  const controller = useFormController({ Schema, validator });

  return (
    <FormProvider controller={controller}>
      <AnswerField />
      <FormActions />
    </FormProvider>
  );
};

4) Connect inputs to form

import { useField } from "@virtuslab/formts";

const AnswerField: React.FC = () => {
  const field = useField(Schema.answer);

  return (
    <section>
      <label htmlFor={field.id}>
        What is the answer to the meaning of life, the universe, and everything?
      </label>
      <input
        id={field.id}
        value={field.value}
        onChange={field.handleChange}
        onBlur={field.handleBlur}
      />
      <div className="error">{field.error}</div>
    </section>
  );
};

5) Connect actions to form

import { useFormHandle } from "@virtuslab/formts";

const FormActions: React.FC = () => {
  const form = useFormHandle(Schema);

  return (
    <section>
      <button
        type="submit"
        disabled={form.isValid === false}
        onClick={() => form.submit(console.log)}
      >
        Submit!
      </button>

      <button type="reset" onClick={form.reset}>
        Reset
      </button>
    </section>
  );
};

Documentation

Currently API documentation is available in form of:

Examples

Play around with the code on CodeSandbox to learn Formts API and features:

a) Step-by-step introduction:

  1. basic form (naive)
  2. basic form + optimized re-renders
  3. basic form + validation
  4. basic form + Material-UI

b) HTML input bindings:

  1. radio group input
  2. checkbox group input
  3. select input
  4. input array
  5. mui multi-select input
  6. mui date-picker input

c) Advanced examples:

  1. change password form
  2. order pizza form
  3. form with summary of validation errors
  4. registration stepper form

Why another form lib?

Update 2023:

Some of the reasons outlined below are no longer valid as react-hook-form has improved since this project started. It offers good type-safety and performance. If for some reason you are not happy with it however, this library offers different approach to many aspects of form management and a powerful validation API - so it may suit your needs better.

a) Type-safety

Most popular form libraries like Formik and react-hook-form are written in Typescript but are not designed with type-safe API as a primary concern.

There is some evidence that this is important for some people:

There are some existing truly type-safe react form solutions, but each has a costly dependency associated with it:

b) Performance

There are SOME form libraries with really good performance (react-hook-form). However combining convenient Context based hook API with React performance optimizations is still problematic. See https://react-hook-form.com/advanced-usage#FormProviderPerformance for example.

c) Declarative validation API

Usually form libs "outsource" advanced validation to schema-based libraries such as Yup. This seems like a great idea but has some limitations:

  • yup and similar packages are not designed with type-safety in mind
  • Advanced optimizations (such as validating only the affected fields rather than the entire form) are not available.

Limitations

  • Form values type is limited by schema definition API and can't represent more advanced TS types
  • Adding required validator does not impact type of values.
  • number() fields are typed as number | "", this is because HTML number inputs work with "" as empty value.
  • Definition of form shape and validation split into 2 separate steps
  • Binding to input components is more verbose than with other form libraries (this is intentional to keep API type-safe and view-layer agnostic)
1.0.1

10 months ago

0.2.29-beta.1

10 months ago

0.2.30

10 months ago

0.2.31

10 months ago

0.2.29

10 months ago

0.2.28

11 months ago

0.2.27

11 months ago

0.2.27-beta.1

11 months ago

0.2.26

1 year ago

0.2.25

1 year ago

0.2.26-beta.2

1 year ago

0.2.26-beta.1

1 year ago

0.2.25-beta.1

1 year ago

0.2.24

1 year ago

0.2.23

1 year ago

0.2.23-beta.1

1 year ago

0.2.22

2 years ago

0.2.21

2 years ago

0.2.20

2 years ago

0.2.19

2 years ago

0.2.18

2 years ago

0.2.17

2 years ago

0.2.21-beta.1

2 years ago

0.2.20-beta.1

2 years ago

0.2.16

2 years ago

0.2.15

2 years ago

0.2.14

3 years ago

0.2.13

3 years ago

0.2.8-beta.1

3 years ago

0.2.8-beta.2

3 years ago

0.2.12

3 years ago

0.2.11

3 years ago

0.2.10

3 years ago

0.2.7

3 years ago

0.2.6

3 years ago

0.2.9

3 years ago

0.2.8

3 years ago

0.2.5

3 years ago

0.2.4

3 years ago

0.2.3

3 years ago

0.2.2

3 years ago

0.2.1

3 years ago

0.2.0

3 years ago

0.1.25

3 years ago

0.1.26

3 years ago

0.1.24-beta.1

3 years ago

0.1.24

3 years ago

0.1.22

3 years ago

0.1.23

3 years ago

0.1.21

3 years ago

0.1.20-beta.3

3 years ago

0.1.20-beta.2

3 years ago

0.1.20-beta.1

3 years ago

0.1.20

3 years ago

0.1.19

3 years ago

0.1.18

3 years ago

0.1.17-beta.1

3 years ago

0.1.17-beta.0

3 years ago

0.1.2-beta.0

3 years ago

0.1.17

3 years ago

0.1.15

3 years ago

0.1.16

3 years ago

0.1.14

3 years ago

0.1.13

3 years ago

0.1.12

3 years ago

0.1.11

3 years ago

0.1.10

3 years ago

0.1.9

3 years ago

0.1.8

3 years ago

0.1.7

3 years ago

0.1.6

3 years ago

0.1.5

3 years ago

0.1.4

3 years ago

0.1.3

3 years ago

0.1.2

3 years ago

0.1.1

3 years ago