Informed
A lightweight framework and utility for building powerful forms in React applications
Install / Use
/learn @teslamotors/InformedREADME
Informed
Introduction
Say hello to the best React form library you have ever used! Informed is an extensive, simple, and efficient solution for creating basic to complex forms in React. Out of the box you get the ability to grab and manipulate values, validate fields, create custom inputs, multi-step forms, array fields, and much much more!
Oh and YES WE USE HOOKS!
Getting Started
Install with npm
npm install --save informed
Live Examples / Docs
What Can it do ?
See for yourself.
By default it comes with native dom inputs that are controlled by informed.
import { Form, Input, Select, Checkbox, Relevant, Debug } from 'informed';
const onSubmit = ({ values }) => console.log(values);
const ExampleForm = () => (
<Form onSubmit={onSubmit}>
<Input name="name" label="Name" placeholder="Elon" />
<Input name="age" type="number" label="Age" required="Age Required" />
<Input name="phone" label="Phone" formatter="+1 (###)-###-####" />
<Select name="car" label="Car" initialValue="ms">
<option value="ms">Model S</option>
<option value="m3">Model 3</option>
<option value="mx">Model X</option>
<option value="my">Model Y</option>
</Select>
<Checkbox name="married" label="Married?" />
<Relevant when={({ formState }) => formState.values.married}>
<Input name="spouse" label="Spouse" />
</Relevant>
<button type="submit">Submit</button>
<Debug />
</Form>
);
Feature List
informed was designed to support many important features
- Arrays: ability to render dynamic arrays of fields
[ 'a', 'b' ]or[ { name: 'Joe', age: 29 }, { name: 'Hope', age: 24 }] - Relevance: ability to render render fields conditionally depending on the state of other parts of the form
- JSPAN: ability to easily and intuitively manipulate form state
- Formatting: ability to perform display formatting, where the format shown to user can differ from the state of the values stored
- Validation: ability to perform both synchronous and asynchronous validation in a controlled manner
- Api: ability to manipulate the form state both inside and outside the context of the form
- State: ability to access field and form data
- Multistep: ability to create dynamic multistep forms
- Scope: ability to scope ( group ) fields
- Schema: ability to render forms based on pure JSON schema
- Dynaic: ability to hide and show fields ( render and unrender ) and either cleanup or maintain state of unmounted fields
- Debugging: ability to easily debug user's state as well as internals of the library
- Nesting: ability to have highly nested value structure
state.values.friends[1].brother.parents.cars[0].model
Creating Your Own Fields
But what if you dont want the out of the box stuff??
No problem, see example below!
import { useForm, useField, Relevant, FormState } from 'informed';
// Step 1. Build your form component ---------------------
const Form = ({ children, ...rest }) => {
const { formController, render, userProps } = useForm(rest);
return render(
<form noValidate {...userProps} onSubmit={formController.submitForm}>
{children}
</form>
);
};
// Step 2. Build your input components --------------------
const Input = props => {
const { render, informed, userProps, ref } = useField({
type: 'text',
...props
});
const { label, id, ...rest } = userProps;
return render(
<>
<label htmlFor={id}>{label}</label>
<input id={id} ref={ref} {...informed} {...rest} />
</>
);
};
const Checkbox = props => {
const { render, informed, userProps, ref } = useField({
type: 'checkbox',
...props
});
const { label, id, ...rest } = userProps;
return render(
<>
<label htmlFor={id}>{label}</label>
<input id={id} ref={ref} {...informed} {...rest} />
</>
);
};
const ErrorInput = props => {
const { render, informed, userProps, fieldState, ref } = useField({
type: 'text',
...props
});
const { label, id, ...rest } = userProps;
const { showError } = fieldState;
const style = showError ? { border: 'solid 1px red' } : null;
return render(
<>
<label htmlFor={id}>{label}</label>
<input id={id} ref={ref} {...informed} {...rest} style={style} />
{showError && <small style={{ color: 'red' }}>{fieldState.error}</small>}
</>
);
};
const Select = props => {
const { render, informed, userProps, ref } = useField({
type: 'select',
...props
});
const { label, id, children, ...rest } = userProps;
return render(
<>
<label htmlFor={id}>{label}</label>
<select id={id} ref={ref} {...informed} {...rest}>
{children}
</select>
</>
);
};
// Step 3. Build your forms! ---------------------------
const onSubmit = ({ values }) => console.log(values);
const ExampleForm = () => (
<Form onSubmit={onSubmit}>
<Input name="name" label="Name" placeholder="Elon" />
<ErrorInput name="age" type="number" label="Age" required="Age Required" />
<Input name="phone" label="Phone" formatter="+1 (###)-###-####" />
<Select name="car" label="Car" initialValue="ms">
<option value="ms">Model S</option>
<option value="m3">Model 3</option>
<option value="mx">Model X</option>
<option value="my">Model Y</option>
</Select>
<Checkbox name="married" label="Married?" />
<Relevant when={({ formState }) => formState.values.married}>
<Input name="spouse" label="Spouse" />
</Relevant>
<button type="submit">Submit</button>
<Debug />
</Form>
);
For Contributors
Design
Informed took the following into consideration when being built:
- Performance:
informedwas designed to be able to handle very complex forms at scale- Ability to render a form with thousands of fields on screen
- Ability to bulk update thousands of fields at a time
- Readability
informedwas designed to be able to write complex forms with very little intuitive code- Reads naturally like with pure JSX:
<Form onSubmit={onSubmit}>
<Input name="name" label="Name" placeholder="Elon" />
<Input name="age" type="number" label="Age" required="Age Required" />
<Input name="phone" label="Phone" formatter="+1 (###)-###-####" />
<Checkbox name="married" label="Married?" />
<Relevant when={({ formState }) => formState.values.married}>
<Input name="spouse" label="Spouse" />
</Relevant>
<Debug />
</Form>
-
ZERO Dependency:
informedwas designed to rely on no other library- exception of a peer dependency react... for now ;)
-
JSON Schema:
informedwas designed to support rendering forms based on pure JSON- this is especially useful when form definitions are stored on the backend
-
Feature List:
informedwas designed to support many important features- Arrays: ability to render dynamic arrays of fields
[ 'a', 'b' ]or[ { name: 'Joe', age: 29 }, { name: 'Hope', age: 24 }] - Relevance: ability to render render fields conditionally depending on the state of other parts of the form
- JSPAN: ability to easily and intuitively manipulate form state
- Formatting: ability to perform display formatting, where the format shown to user can differ from the state of the values stored
- Validation: ability to perform both synchronous and asynchronous validation in a controlled manner
- Api: ability to manipulate the form state both inside and outside the context of the form
- State: ability to access field and form data
- Multistep: ability to create dynamic multistep forms
- Scope: ability to scope ( group ) fields
- Schema: ability to render forms based on pure JSON schema
- Dynaic: ability to hide and show fields ( render and unrender ) and either cleanup or maintain state of unmounted fields
- Debugging: ability to easily debug user's state as well as internals of the library
- Nesting: ability to have highly nested value strucutre
state.values.friends[1].brother.parents.cars[0].model
- Arrays: ability to render dynamic arrays of fields
Terminology
- JSPAN: ( Java Script Path Access Notation ) much like how you access and write to objects and arrays in javascript you can use the string representation to address a place in an object.
const path = 'state.values.friends[1].brother.name';
Layout
This project cotains three important directories, src, vitedocs, and __tests__
Note: some things were left out as they are not super important or are going to be deprecated or removed in future.
project_root
│
├── index.d.ts # all of informeds types live here
│
├── src # all of informeds source code lives here ( except types index.d.ts )
│ ├── components # React Components
│ ├── hooks # Hooks
│ ├── Context.js # Internal Contexts used in this library
│ ├── debug.js # Basically the https://github.com/visionmedia/debug library but shrunk down
│ ├── fieldMap.js # Default field adapter, used when working with schema forms
│ ├── index.js # all external exports ( everything exposed to users )
│ ├── ObjectMap.js # internal data structure for manipulating the form state objects
│ ├── FormController.js # The brains behind the library, this controls basically everything :)
│ └── utils.js #
