react-informed
TypeScript icon, indicating that this package has built-in type declarations

1.9.2 • Public • Published

Informed is a set of components to reduce the work needed to create forms with react.

There are already many different form solution in the react ecosystem. Informed tries to be different by minimizing boilerplate. Informed does not require decorated input elements, either. Typescript definitions are provided for easier form refactoring.

Click here to view a demo.

<Form value={form}
      preventAction={true}
      onChange={(form) => this.setState({form})}>
 
    <div>
        <label htmlFor={form.firstName.name}>First Name</label>
        <Field value={form.firstName} 
               debounce={50}>
            <input type="text"
                   placeholder="First Name"
                   disabled={form.isSubmitted}
            />
        </Field>
    </div>
 
    <div>
        <label htmlFor={form.lastName.name}>Last Name</label>
        <Field value={form.lastName}
               debounce="onBlur">
            <input type="text"
                   placeholder="Last Name"
                   disabled={form.isSubmitted}
            />
        </Field>
    </div>
 
    <div>
        <button disabled={!form.isValid || form.isSubmitted}
                className="btn btn-primary"
                type="submit">
            submit
        </button>
    </div>
</Form>

Run examples

See the docs/examples/ directory for examples on how to use this library. To run the examples locally:

npm install
npm start 

and open your browser to http://localhost:8000/ (if it doesn't open automatically)

Goals

  • Input elements should not be passed as props or wrapped in odd ways.
    • There should be full control over look and feel using standard HTML props
  • Un-opinionated about how form state is stored
    • set the form based on props like with a redux-store sol'n
    • or make use of a containing component's state
  • Easily integrates custom components (just implement the value/onChange interface)
  • Typescript integration
  • limit the amount of unnecessary boilerplate needed for controlled elements by automatically adding the needed value/onChange props

Form State Object

Every Form state object implements the BaseForm interface. There are several fields that provide summary info about the form (is<*>).

export interface BaseForm {
    /** true if the form was submitted. */
    isSubmitted?: boolean;
    /** true if any of the form fields have errors. If a field can only have an error if it is dirty.  */
    isError?: boolean;
    /** true if there are no errors on any fields. Unlike isError, this checks fields regardless of their dirty flag. */
    isValid?: boolean;
    /** true if the form values are different from their original values */
    isChanged?: boolean;
 
    [k: string]: any;
}

Finally, each Field is stored as a property where the name of the Field is set to an InputState object.

InputState

Each InputState object has several properties that get updated automatically allowing to easily update the UI in response to events like form errors.

There may be some confusion about the difference between error and honestError. For example, a that is required but initialized with an empty value will immediately have an error. But we wouldn't really indicate an error unless the user had attempted to modify the input and then left its value blank. To avoid having to perform tests against the dirty property, the error property is provided.

export interface InputState<T> {
    /** property name of Field */
    name: string;
    /** Non-zero when the Field has an error (always 0 when dirty === false) */
    error: number;
    /** Non-zero when the Field has an error. Even when dirty === false) */
    honestError: number;
    /** value of Field*/
    value: T;
    /** True if the user has changed the form. Initial value is false */
    dirty: boolean;
    /** true if the current value is different (shallow comparison) from the original */
    changed: boolean;
}

Field Usage

should be a direct wrapper around the input element or custom component you want to use. If you need to use a

or similar to control positioning this should be placed around instead.

If you look at the inspected html you can see that does not create a wrapper

element that would impact your layout. Field will directly render its child, so configure whatever props you want. But do not set value or onChange. those props will be overwritten. Both of those are accessible on the component so make use of them there.

Save Form State

The element is configured like a regular controlled component. Implement the 'value' and 'onChange' props and the rest of the form takes care of itself

    <Form value={form}
          onChange={(form) => this.setState({form})}>
          ...
    </Form>

Future Goals and TODOs

  • Field does not update when props of a Field is changed manually
  • 'validate' prop interface should accept a Promise for async validation

Examples

  • classic POST form

Package Sidebar

Install

npm i react-informed

Weekly Downloads

0

Version

1.9.2

License

ISC

Last publish

Collaborators

  • derekhawker