FormManager ('FM') is collection of data-handling tools for form-data, or any data actually. The motivation for this helper is to have a total data solution for forms, which can virtually eliminate the need for custom code.
Form Integration
- Compatible with ANY UI library, including React
- Integration with any type of form control, standard or custom
- Manages data internally; does not require a
<form>
element - Optimizations for use with Material UI controls
- Form-field property-setter helpers to simplify form markup
- Form-field event handling, with customizable validation events
- Generates relevant ARIA attributes to improve accessibility
- Can alias fieldnames, to normalize names or to flatten nested data
- Development tools for testing and refining form configurations
Data Validation & Error Messages
- Comprehensive validation of data; most common validators are built-in
- Configuration options at both the form and field level for maximum control
- Multiple validation options, automatically linked to error-messages
- Error-message auto-generation, using a templating system
- Automatic error output with Material UI; or simple output without
Data Handling
- Maintains 4 data caches: server-data, form-values, initial-data, and state
- Automated data-type and format conversion between form-data and field-values
- Parsing, cleaning and reformatting of form-field entries
- Change-tracking, undo capability
FM does NOT do/require:
- Does not require any special markup or structure
- Does not 'render' anything, but does auto-generate field props
- Does not 'wrap' forms; it is agnostic about form layout
- Does not fetch or post data, but does provide post-ready data
- Does not create global vars (unless imported as a
<script />
) - Does not use Context in React or similar trickery
FM is just ordinary Javascript. There is no magic!
Try the demos at: https://allpro.github.io/form-manager
Play with the demo code at: https://codesandbox.io/s/github/allpro/form-manager/tree/master/example
If you pull or fork the repo, you can run the demos like this:
- In the root folder, run
npm start
- In a second terminal, in the
/example
folder, runnpm start
- The demo will start at https://localhost:3000
- Changes to the component or the demo will auto-update the browser
- NPM:
npm install @allpro/form-manager
- Yarn:
yarn add @allpro/form-manager
- CDN: Exposed global is
FormManager
- Unpkg:
<script src="https://unpkg.com/@allpro/form-manager/umd/@allpro/form-manager.min.js"></script>
- JSDelivr:
<script src="https://cdn.jsdelivr.net/npm/@allpro/form-manager/umd/@allpro/form-manager.min.js"></script>
- Unpkg:
No form helper I've found matches FM's data handling capabilities. Some helpers focus on backend communications, with no built-in validation. For me, validation and error message handling is vital for forms, whereas communications is not something I need or want a form-helper to do.
Most form helpers don't provide value-formatting or data-conversion capabilities, so you must write this yourself, repetitively. FM integrates all data manipulation features, so they are simple options.
Most form helpers requires special markup, which adds complexity. This means 'presentation components' contain form logic and therefore are not as simple and 'dumb' as they should be. FM provides a total separation of concerns, making components simpler.
FormManager centralizes all data handling and logic,
separated from any form markup.
If you have a large form configuration,
it's can even go its own file, like formConfig.js
.
If you already use other helpers, like a validation system, it can be easily integrate with FM events and configuration. Every feature in FM is easily extended or overridden.
I created FM when using Material UI components in a large React app. However, FM is not dependent on React, Material-UI, or any other library. It can be used in any Javascript environment.
FM is designed for professional developers with diverse needs. It handles rich forms using a wide range of controls, in potentially complex designs. There are no limitations on what form FM can handle.
Even a junior dev can learn the basics of FM very quickly. Existing forms require no changes other than changing their attributes/props. See the 'Simplest Form Example' below to see how easy it can be.
FM uses standard properties and events to integrate with form controls. Below are examples of basic form control markup. FM property-setter helpers are used to set many properties at once. These examples uses React JSX markup, but that's not a requirement.
// Native control, with manual error output
<input {...form.fieldProps('firstName')} />
{ form.hasError('firstName') &&
<p>{form.getError('firstName'}</p>
}
// Material UI control using props setter, including error messages
<TextField {...form.allMuiProps('firstName') />
// Custom date-picker control
<DatePicker {...form.fieldProps('birthdate')} />
All FM configuration is optional. If you don't want validation, data-conversion, or other special features, then you don't need any form configuration at all! This example illustrates the simplest possible form, where FM is used just to handle fields and track the form-data. (This example uses a React Hooks component.)
function SimpleNameForm(props) {
const form = useFormManager({}, props.data);
return (
<div>
<label>First Name: <input {...form.fieldProps('firstName')} /></label>
<label>Middle Name: <input {...form.fieldProps('middleName')} /></label>
<label>Last Name: <input {...form.fieldProps('lastName')} /></label>
<button
disabled={form.isClean()}
onClick={() => postToServer(form.changes())}
>
Save Changes
</button>
</div>
);
}
Note that there is no 'state', no event handlers, and no logic.
FM handles everything. It knows if anything changed
(isClean()
/isDirty()
), and if so,
then which data needs to be updated (changes()
).
The sample form below uses Material UI TextFields.
A formManager
instance is created in the parent, container component,
then passed down as props.form
.
The form.allMuiProps('fieldname')
helper adds up to 11 properties and
3 event handlers. This gives FM full control of each field,
including automatically displaying error-messages when applicable.
NOTES
- No form configuration exists inside this component.
- There is no
<form>
element — it's not necessary. FormManager IS the form! - The
form.submit
method shown is NOT part of FM. It's a container method attached to FM because it provides intuitive semantics, and avoids an extra prop.
const MyForm = (props) => {
const { form } = props;
return (
<div>
<TextField label="First Name" {...form.allMuiProps('firstName')} />
<TextField label="Last Name" {...form.allMuiProps('lastName')} />
<TextField label="Address" {...form.allMuiProps('address')} />
<TextField label="City" {...form.allMuiProps('city')} />
<TextField label="State" {...form.allMuiProps('state')} />
<TextField label="Country" {...form.allMuiProps('country')} />
<TextField label="Phone" {...form.allMuiProps('phone')} />
<TextField label="Email" {...form.allMuiProps('email')} />
<div>
<Button color="primary" onClick={form.submit}>
Submit
</Button>
<Button color="secondary" onClick={form.reset}>
Undo Changes
</Button>
</div>
</div>
);
}
ALL form options and logic is set in the form-configuration.
This presentation components is 'dumb' so it can focus on appearance.
Cosmetic properties can be added to fields or components as normal.
Field 'labels' are just a cosmetic presentation choice.
However, FM accepts a 'displayName' for use in error messages and an
auto-generated aria-label
attribute.
(aria-invalid
is also auto-generated)
FM easily handles very complex custom forms. For example,
a form can spans multiple screens, with some controls inside modal popups.
Just pass props.form
to integrate any sub-component with a FM instance.
See Implementing FormManager in Components for details.
Documentation is spread across multiple files...
The FM object has a rich API. It provides integration with form-field components, plus many methods for interacting with data. Every feature of FM can be controlled programmatically when necessary.
See FormManager API Reference for details.
The power of FM is in its configuration. This is generally passed-in when creating a FM instance. However every configuration option can also be changed on-the-fly.
See FormManager Configuration for details.
FM caches and manages all relevant data, including a custom 'form state'. It automatically transforms complex JSON structures into a flat-structure suitable for form-values. It can also clean, reformat, transform and validate field values. All features are enabled with simple configuration options.
See FormManager Data Handling for details.
Validation is a key feature of FM. It makes field validation and error handling as easy as possible. As with all other features, validation rules and error messages are specified in the form config - not inside the presentation components.
See FormManager Validation for details.
FM can be used any way you want. One pattern is to
implement it in a 'container component' that handles the data and view logic.
There is also a useFormManager
hook, to integrate with components
that use React Hooks.
See Implementing FormManager in Components for details.
FM exposes most of the utility methods it uses internally.
These helpers can be imported and used separately from FM
if you find any useful.
For example, it exposes parseDate()
and formatDate()
helpers
that might serve your date handling needs.
See Exported Helpers for details.
FileManager is fully functional. I have used it in multiple projects. However, this version is still undergoing refinement so it's possible that some temporary bugs may appear.
Over the next weeks I'll add tests to confirm that everything is working, and continues to work as specified when I do updates.
I'll also complete the documentation, which is currently a work-in-progress.
If you are already using FM, check back regularly for updates.
Once these tasks are completed I'll bump the version to 1.0.0.
- create-react-library - A React component framework based on create-react-app
Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.
We use SemVer for versioning. For the versions available, see the tags on this repository.