mui-form-components
v1.3.2
Published
Utility wrappers and hooks for managing forms with react and material ui
Downloads
5
Readme
MUI Form Components
Opinionated utility wrappers and hooks for managing forms with react and material ui.
Purpose
The purpose of this library is to make the process of building high performance forms as easy as possible. With a few opinionated assumptions about how form UX should work, this library exports a useForm
hook along with a handful of Material-UI form components that have been wrapped with utilities like validation and state management.
Quick Start
Install
npm install mui-form-components
Simple Usage:
import {TextField, useForm} from 'mui-form-components';
import Button from '@mui/material/Button';
const MyForm = () => {
const {valid, data, form, reset} = useForm();
const handleSubmit = useCallback(() => {
console.log('Do something with this form data: ', data)
reset();
}, [])
return (
<div>
<TextField
form={form}
name="firstName"
label="First name"
/>
<Button
onClick={handleSubmit}
disabled={!valid}
>
Submit
</Button>
</div>
)
}
The problem
Lets look at some of the things a developer would typically have to ask themselves when building a form with React and Material-UI.
- State management: Does each input rely on its own
useState
value or is there a single object with key/value pairs? - Validation: When does input validate occur? How does it change based on the approach to state management? How often (fast) does it need to occur? How will we know when the entier form is valid or invalid?
- Errors: How and when should errors be displayed? How should one treat network errors versus local state validation errors?
- User experience: When should inputs be rendered red? When should helper text appear? When should inputs no longer be rendered red? When should helper text disappear?
- Form resets: How should resetting the form work? How do we get validation to play nice when resetting values to something invalid?
- Performance: Form inputs need to render quickly enough to keep up with a user's typing speed. This means an input needs to be able to re-render as quickly as ten times every second (or more). In a complex form that is managing state, validation, and other effects running every 10 milliseconds or so, performace issues can become apparent. How do we mitigate this?
The approach we take
Lets look at how mui-form-components
approaches each of these problems. Taking the example from above:
- State is managed automatically by the
useForm
hook, based on thename
prop. Data would end up looking like{firstName: 'bob'}
. - Validation of individual inputs is handled directly in the input itself, not in the
useForm
hook or your parent component. In the text field, the input is validated on every change event, so the input itself runs fast and knows exactly when it becomes invalid / valid. The value of the input (plus meta data on its validity) is debounced and communicated back up to theuseForm
hook (and your component) once every 150 milliseconds. This is fast enough for the user to barely perceive a delay, but a 15x reduction in the amount of timesuseHook
and your component need to re-render. Again, the input renders in real time, but your compoent renders only when the input sends an updated value. This means you can have a submit button change its disabled state based on whether the entire form is valid or not. - Network errors are managed by you, but inputs manage their own error state automatically based on their validators. There are a set of deafult validators for each "type" of input. If an input of type "text" is marked as required, it must have at least 2 characters present in order to be considered valid. Inputs of type "email" must be a valid email, etc.
- UX: The approach here is generally thus: A required text input starts with no value, and is therefore "not valid". However, we don't want to render a blood-red form with a bunch of helper text all over the place before a user has had a chance to type anything. Therefore, required inputs are only rendered with errors if the input has been focused and then blurred. Helper text is only rendered when an input has been blurred and contains a non-empty, non-valid value.
- Resets: Sometimes you need to reset a form back to its original state. The
useForm
hook provides a reset function that can be called to do just that. - Performance: Because we let the leaves (inputs) do the real-time validity checks, and only update the tree (your component) after a debounced 150 milliseconds, we avoid a ton of extraneous calls (and therefore, as the thinking goes, performance hits)