Package Exports
- react-pathform
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (react-pathform) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
react-pathform
Pathform was built to scratch an itch for recursive, nested, dynamic forms. Using paths as an array, we can spread dynamic paths around like butter.
We can derive a lot from the path... Why?
Quick Start
npm install --save react-pathformimport React from 'react';
import { PathFormProvider, PathForm, PathFormField } from 'react-pathform';
import { Button, TextField } from '@material-ui/core';
function App() {
return (
<PathFormProvider
initialRenderValues={{
nested: {
items: [{ name: "Joey Joe Joe Jr." }]
}
}}
>
<PathForm onSubmit={(values) => alert(JSON.stringify(values, null, 2))}>
<PathFormField
path={["nested", "items", 0, "name"]}
defaultValue=""
render={(inputProps, meta) => {
return (
<TextField
label="Name"
error={!!meta.error}
helperText={meta.error?.message}
{...inputProps}
/>
);
}}
/>
<Button type="submit">Submit</Button>
</PathForm>
</PathFormProvider>
);
}Example Code
Check out the Example App
CodeSandbox Examples
API
- Components
- Hooks
PathFormProvider (required)
The store context provider for your form. You must place it at the root of your form to be able to use usePathForm, and PathForm* components.
The data in the store will remain until the PathFormProvider is unmounted.
| Prop | Type | Description |
|---|---|---|
| initialRenderValues | any | The data for your form on the initial render only. |
PathForm
Replaces a native form element and allows you to hook into onValidate and onSubmit.
| Prop | Type | Description |
|---|---|---|
| onValidate | callback(values) or Promise<callback(values)> | Called just before submitting. |
| onSubmit | callback(values) or Promise<callback(values)> | Called if validation passes for submission. |
PathFormField
Binds to a value at the given path in the store from.
| Prop | Type | Required | Description |
|---|---|---|---|
| path* | PathFormPath | Yes | The path selector to the item in your store. |
| render* | callback(inputProps, meta) | No | The callback to render your component. inputProps The input props for your form component. meta Meta properties of the store item. |
| defaultValue | any | No | The value use on the initial render, if the store item does not already exist. If not set, you may receive a warning about switching from uncontrolled to controlled. |
PathFormArray
Binds to an array at the given path in the store from. The render callback will be called for
each item in the array.
Use the meta.uuid on your root item key.
EG: key={meta.uuid}
| Prop | Type | Required | Description |
|---|---|---|---|
| path* | PathFormPath | Yes | The path selector to the item in your store. |
| render* | callback(arrayProps, meta) | No | The callback to render your component. inputProps The input props for your form component. meta Meta properties of the store item. |
| defaultValue | any | No | The value use on the initial render, if the store item does not already exist. |
usePathForm
Use this hook from any child component scope to access the context of your form.
Returns the form context provider object with helper functions:
const { setValue, setTouched, addError, clearError, array } = usePathForm();setValue(path: PathFormPath, value: any)
Sets the store item value at the given path.
setTouched(path: PathFormPath, touched: boolean)
Marks the store item at the given path as touched.
addError(path: PathFormPath, error: PathFormError)
Adds an error at the given path.
clearError(path: PathFormPath)
Clears an error at the given path.
array: PathFormArrayUtils
An object of utilities for mutating array items in your form.
const { array } = usePathForm();append function(path: PathFormPath, item: any)
Appends an item to the end of the array at given path.
array.append(["deeply", "nested", "items"], { "name": "Santa's Little Helper" });prepend function(path: PathFormPath, item: any)
Prepends an item to the beginning of the array at given path.
array.prepend(["deeply", "nested", "items"], { "name": "Santa's Little Helper" });move function(path: PathFormPath, fromIndex: number, toIndex: number)
Moves an item in the array at given path, from the fromIndex to the toIndex. Useful for reordering items.
array.move(["deeply", "nested", "items"], 3, 4);remove function(path: PathFormPath, index: number)
Removes an item from the array at given path at index.
array.remove(["deeply", "nested", "items"], 2);usePathFormValue
Returns an array of [value, meta] at the given path.
const [nameValue, nameMeta] = usePathFormValue(['person', 'name']);
const [ageValue, ageMeta] = usePathFormValue(['person', 'age']);Types
PathFormPath
type PathFormPath = Array<string | number>;
const path: PathFormPath = ["deeply", "nested", "items", 0, "children", 0, "name"];The path to an item in your form.
Strings imply object property.
Numbers imply array index.
PathFormError
type PathFormError = {
type: string;
message: string;
value: any;
};PathFormStoreMeta
type PathFormStoreMeta = {
uuid: string;
dirty: boolean;
touched: boolean;
error: null;
};But Y Tho?
I have loved many form react form libraries (wow, holy nerd right?). I have gone from redux-form to react-final-form to formik to react-hook-form. They are all amazing libraries. This project aims to provide all the best things from each library: the global control of redux-form, the observable model of react-final-form, the api of formik, and the performance of react-hook-form.
These libraries use the native input property name as a dot notation string to bind or select data:
const name = "deeply.nested.items[0].children[0].name";Whereas this library derives the name from a path. The difference is,
you can easily spread arrays, not strings.
const parentPath = ["deeply", "nested", "items"]; // name = "deeply.nested.items"
const childPath = [...parentPath, itemIndex, "children"]; // name = "deeply.nested.items[0].children"
const deepPath = [...childPath, childIndex, "name"]; // name = "deeply.nested.items[0].children[0].name"This makes nested / recursive form components much cleaner.

The internal form store wraps the form structure alongside meta next to values.
Values in the store are either an object, array, or primitive.
Objects and Arrays can have both child items, but only array is iterable.
Primitive values cannot have any children.
Feature Checklist
| Category | Criteria | Complete |
|---|---|---|
| README | Feature Checklist | ☑ |
| README | Quick Start | ☑ |
| README | Simple CodeSandbox | ☑ |
| README | API | ☐ |
| Library | onValidate | ☐ |
| Library | onSubmit | ☐ |
| Library | reset | ☐ |
| Library | touched & validation | ☐ |
| Library | Built in validation | ☐ |
| Examples | Example App | ☐ |
| Examples | Codesandbox | ☐ |
| Bundle Size | Optimize UUID | ☐ |
| Bundle Size | Optimize Lodash | ☐ |
| README | Contributing | ☐ |