README
Form Mate
A tiny and elegant library to handle forms with React:
import Form from "form-mate";
// { fullname: "Francisco", email: "xxxxxx@francisco.io" }
export default () => (
<Form onSubmit={data => console.log(data)}>
<input name="fullname" required />
<input name="email" type="email" required />
<button>Subscribe!</button>
</Form>
);
Benefits over a plain <form>
:
- Parse the form fields into an object for easy access and consumption. Now you can do
onSubmit(item => setItems([...items, item]))
. - Disable the form while it's submitting to avoid double-submit.
- Prop
onError
for easy error handling, integrates well with other options. - Prop
onChange
to listen to the form changes as they happen. - Prop
autoReset
to clear the form afteronSubmit
finishes successfully. - Prop
encType
(likeencType="multipart/form-data"
) for file handling. It makes the callback receive an instance ofFormData
instead of a plain object. This makes it easy to submit files withfetch()
, Axios, etc.
Getting Started
Install form-mate
with npm:
npm install form-mate
Import it and use it anywhere in your React project:
import Form from "form-mate";
export default () => (
<Form onSubmit={data => console.log(data)} autoReset>
{/* ... */}
</Form>
);
API
onSubmit
Mandatory prop that accepts a sync or async
callback. It will receive the values in the form when submitted:
import Form from "form-mate";
export default function Subscribe() {
return (
<Form onSubmit={data => console.log(data)}>
<input name="name" defaultValue="Francisco" />
<input name="subscribe" defaultChecked type="checkbox" />
<input name="terms" value="accepted" defaultChecked type="checkbox" />
<input name="gender" value="female" type="radio" />
<input name="gender" value="male" defaultChecked type="radio" />
<button>Subscribe!</button>
</Form>
);
}
// {
// name: "Francisco",
// subscribe: "on", // The default when no "value" is provided
// terms: "accepted",
// gender: "male"
// }
It prevents the default action automatically. See the tests for more examples of how the fields are parsed.
onError
Optional prop to handle any error happening in the onSubmit
. This allows the onSubmit to fail as desired. Works well with both sync and async onSubmit
:
import Form from "form-mate";
export default () => {
const [error, setError] = useState();
const onSubmit = data => {
throw new Error("Aaaaagh");
};
return (
<Form onSubmit={handleForm} onError={setError} autoReset>
{error ? <p>{error.message}</p> : null}
<input name="fullname" required />
<input name="email" type="email" required />
<button>Subscribe!</button>
</Form>
);
};
onChange
Listen to the forms' changes in fields as they happen. It will be triggered on every keystroke, on every click (that changes the data), etc:
import Form from "form-mate";
export default function Subscribe() {
return (
<Form onChange={data => console.log(data)}>
<input name="name" defaultValue="Francisco" />
<input name="subscribe" defaultChecked type="checkbox" />
<input name="terms" value="accepted" defaultChecked type="checkbox" />
<input name="gender" value="female" type="radio" />
<input name="gender" value="male" defaultChecked type="radio" />
<button>Subscribe!</button>
</Form>
);
}
autoReset
By default the form is not reset after it's submitted. This prop can make the form to reset after the onSubmit callback has resolved successfully:
<Form onSubmit={...} autoReset>...</Form>
Even with this prop, the form will not be reset if the onSubmit
throws an error (sync or async).
This prop is very useful when adding new items to a list in succession, see codesandbox example.
encType
The encType can be set to multipart/form-data
to upload files:
import Form from 'form-mate';
export default() => (
<Form onSubmit={...} encType="multipart/form-data">
<input name="name" />
<input type="file" name="file" />
<button>Send</button>
</Form>
);
In that case, the argument data
passed to the onSubmit will not be a plain object, it will be an instance of FormData
instead.
Examples
Add items to a list
A fully working shopping list example (see codesandbox):
import React, { useState } from "react";
import Form from "./Form";
export default function Groceries() {
const [items, setItems] = useState([]);
return (
<ul>
{items.map(item => (
<li key={item.text}>
{item.text} × {item.quantity}
</li>
))}
<li>
<Form onSubmit={item => setItems([...items, item])} autoReset>
<input name="text" placeholder="Item to buy" autoFocus />
{" × "}
<input type="number" name="quantity" defaultValue={1} />
<button>Add!</button>
</Form>
</li>
</ul>
);
}
Upload files with React
To upload files with React and Axios, you can do it like this:
import Form from 'form-mate';
export default function App() {
const onSubmit = data => {
// Send the data to the server
await axios.post("/hello", data, { "Content-Type": "multipart/form-data" });
};
return (
<Form onSubmit={onSubmit} encType="multipart/form-data">
<input name="name" />
<input type="file" name="file" />
<button>Send</button>
</Form>
);
}