Description
So why write yet another form utility you might ask? First off, I don't like the Formik approach. In my humble opition formik is very verbose and requires lots of boilerplate. Also does not work with hooks. react-hook-form is a very cool library and it is the main inspiration for formhero. It does almost everything right... typescript, no deps, small, concise.
The problem that I found while using it was that 3rd party ui libs like Ant Design or Fabric UI do not always have the standart onChange or value props in their components. That is where react-hook-form starts falling apart. This is what formhero tries to address in the most minimalistic way possible, with as little code as needed. All in pure typescript and no deps.
formhero alternatives and similar libraries
Based on the "Form Widgets" category.
Alternatively, view formhero alternatives based on common mentions on social networks and blogs.
-
jQuery-File-Upload
File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads. -
Joplin
Joplin - the secure note taking and to-do app with synchronisation capabilities for Windows, macOS, Linux, Android and iOS. -
select2
Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results. -
Sortable Β
Reorderable drag-and-drop lists for modern browsers and touch devices. No jQuery or framework required. -
chosen
Deprecated - Chosen is a library for making long, unwieldy select boxes more friendly. -
fullcalendar
Full-sized drag & drop event calendar in JavaScript -
bootstrap-datepicker
A datepicker for twitter bootstrap (@twbs) -
dropzone
Dropzone is an easy to use drag'n'drop library. It supports image previews and shows nice progress bars. -
typeahead.js
typeahead.js is a fast and fully-featured autocomplete library -
selectize.js
Selectize is the hybrid of a textbox and <select> box. It's jQuery based, and it has autocomplete and native-feeling keyboard navigation; useful for tagging, contact lists, etc. -
Date Range Picker
JavaScript Date Range, Date and Time Picker Component -
bootstrap-select
:rocket: The jQuery plugin that brings select elements into the 21st century with intuitive multiselection, searching, and much more. -
fine-uploader
Multiple file upload plugin with progress-bar, drag-and-drop, direct-to-S3 uploading. -
tui.calendar
ππ A JavaScript calendar that has everything you need. -
Pikaday
A refreshing JavaScript Datepicker β lightweight, no dependencies, modular CSS -
pickadate.js
The mobile-friendly, responsive, and lightweight jQuery date & time input picker. -
plupload
Plupload is JavaScript API for building file uploaders. It supports multiple file selection, file filtering, chunked upload, client side image downsizing and when necessary can fallback to alternative runtimes, like Flash and Silverlight. -
awesomplete
Ultra lightweight, usable, beautiful autocomplete with zero dependencies. -
jQuery-Autocomplete
Ajax Autocomplete for jQuery allows you to easily create autocomplete/autosuggest boxes for text input fields -
Choices.js
A vanilla JS customisable select box/text input plugin β‘οΈ -
selectize.js (old)
Selectize is the hybrid of a textbox and select box. It's jQuery based and it has autocomplete and native-feeling keyboard navigation; useful for tagging, contact lists, etc. -
FileAPI
FileAPI β a set of javascript tools for working with files. Multiupload, drag'n'drop and chunked file upload. Images: crop, resize and auto orientation by EXIF. -
tag-it
A jQuery UI plugin to handle multi-tag fields as well as tag suggestions/autocomplete. -
jQuery-Tags-Input
Magically convert a simple text input into a cool tag list with this jQuery plugin. -
flow.js
A JavaScript library providing multiple simultaneous, stable, fault-tolerant and resumable/restartable file uploads via the HTML5 File API. -
rome
:calendar: Customizable date (and time) picker. Opt-in UI, no jQuery! -
jquery multi-select
A user-friendlier drop-in replacement for the standard select with multiple attribute activated. -
Garlic.js
Automatically persist your forms' text and select field values locally, until the form is submitted. -
analytics
Lightweight analytics abstraction layer for tracking page views, custom events, & identifying visitors -
datedropper
datedropper is a jQuery plugin that provides a quick and easy way to manage dates for input fields. -
Countable
Add live paragraph-, word- and character-counting to an HTML element. -
Duet Date Picker
Duet Date Picker is an open source version of Duet Design Systemβs accessible date picker. Try live example at https://duetds.github.io/date-picker/ -
Placeholders.js
A JavaScript polyfill for the HTML5 placeholder attribute -
JavaScript-autoComplete
An extremely lightweight and powerful vanilla JavaScript completion suggester. -
Syncfusion JavaScript UI Controls
Syncfusion JavaScript UI controls library offer more than 50+ cross-browser, responsive, and lightweight HTML5 UI controls for building modern web applications. -
Ajax Bootstrap Select
This uses the bootstrap-select plugin and extends it so that you can use a remote source to search. -
Amazon Autocomplete JS Plugin
π Unlock the full power of the Amazon autocompletion engine right into your search input. JavaScript Plugin. -
HTML5 AJAX File Uploader
JavaScript library that manages file uploads using html5 drag and drop and file API's. -
Lean-Mean-Drag-and-Drop
Drag&Drop Sorting and Reordering script for complex nested structures
Appwrite - The open-source backend cloud platform
* Code Quality Rankings and insights are calculated and provided by Lumnify.
They vary from L1 to L5 with "L5" being the highest.
Do you think we are missing an alternative of formhero or a related project?
README
Fully customisable react form utility.
π Features
- Typescript compatible
- Customizable extractor, validator, getter and setters. (More in the docs)
- 0 Dependencies
- Tiny ~0.7kB
- React Hooks
Installation
npm i formhero
Note: Requires at least typescript version 3.5
, otherwise the error object will not have the right inherited types.
π Demos
π Docs
- [Examples](#-examples-more-here)
- [Docs](#-documentation)
- Contructor
- Initial State
- Validators
- Options
- Returns
- field
- form
- errors
- isValid
- setField
- setForm
- setErrors
π€ Motivation & Why
So why write yet another form utility you might ask? First off, I don't like the Formik approach. In my humble opition formik is very verbose and requires lots of boilerplate. Also does not work with hooks. react-hook-form is a very cool library and it is the main inspiration for formhero. It does almost everything right... typescript, no deps, small, concise.
The problem that I found while using it was that 3rd party ui libs like Ant Design or Fabric UI do not always have the standart onChange
or value
props in their components. That is where react-hook-form starts falling apart. This is what formhero tries to address in the most minimalistic way possible, with as little code as needed. All in pure typescript and no deps.
π Quickstart
import ReactDOM from 'react-dom'
import { useForm } from 'formhero'
const Form = () => {
const { field, form } = useForm({
username: '',
password: '',
})
const _submit = (e: React.FormEvent) => {
e.preventDefault()
console.log(form)
}
return (
<div>
<form onSubmit={_submit}>
<input {...field('username')} />
<input {...field('password')} />
<button type="submit">Go π</button>
</form>
</div>
)
}
π₯ Examples (More Here)
Validation
const Form = () => {
const { field, form, errors } = useForm(
{
username: '',
email: '',
password: '',
},
{
username: value => value.length > 3,
email: {
validator: /@/,
message: 'Must contain an @',
},
password: [
{
validator: /[A-Z]/,
message: 'Must contain an uppercase letter',
},
{
validator: /[\d]/,
message: 'Must contain a digit',
},
],
}
)
return (
<form>
<h1>Errors & Validation</h1>
<input {...field('username')} placeholder="Username" />
{errors.username && 'Must be longer than 3'}
<input {...field('email')} placeholder="EMail" />
{errors.email}
<input {...field('password')} placeholder="Password" type="password" />
{errors.password}
</form>
)
}
Easy Customization
Often it happens that you use a specific input or framework, so the default getter, setter and extractor for the event won't cut it. No worries: formhero got you covered!
const Form = () => {
const { field, form, errors } = useForm({
awesome: true,
})
return (
<form
onSubmit={e => {
e.preventDefault()
console.log(form)
}}
>
<h1>Custom</h1>
<label>
<input
type="checkbox"
{...field('awesome', {
setter: 'checked',
getter: 'onChange',
extractor: e => e.target.checked,
})}
/>
Is it awesome?
</label>
<input type="submit" />
</form>
)
}
Dynamic Fields
Sometimes you don't know all the fields upfront. You can simply define a generic type and assign it to the initial object. Of course type assistance is limited in this case as formhero cannot be sure what keys are valid.
import React from "react";
import ReactDOM from "react-dom";
import { useForm } from "formhero";
type MyForm = { [field: string]: string | number };
const init: MyForm = {
username: "unicorn",
password: ""
};
const Form: React.FC = () => {
const { field, form, errors } = useForm(init);
return (
<form>
<input {...field("username")} placeholder="Username" />
<input {...field("someother")} placeholder="Something else" />
<input {...field("password")} placeholder="Password" type="password" />
</form>
);
};
π Documentation
useForm
const { field, errors, update, form, isValid } = useForm(initial, validators, options)
Initial
This is the base state of the form. Also the typescript types are inhered by this.
Example
const initial = {
username: 'defaultValue',
password: '',
rememberMe: true,
}
Validators
A validator is an object that taked in either a RegExp
or a Function
(can be async) or an array of those. Optionally you can pass a message string that will be displayed instead of the default one.
A validator functions takes the current value as input and should return a boolean
or a string
. If returned true
the input counts as valid, if false
it's not. If you pass a string formhero will treat it as not valid and display the string returned as error message.
Example: Regular Expression
const validators = {
// Only contains letters.
// This could also be a (also async) function that returns a boolean.
username: /^[A-z]*$/,
}
Example: Function
const validators = {
username: (value: string) => value.lenght > 3,
}
Example: With Object
const validators = {
username: {
validator: /^[A-z]*$/,
message: 'My custom error message',
},
}
Example: Multiple Validators
const validators = {
username: [
{
validator: /^[A-z]*$/,
message: 'My custom error message',
},
/[\d]/,
async value => value.length > 0,
{
validator: value => true,
message: 'Some other error',
},
],
}
Example: Dynamic Error Message
const validators = {
username: async (s: string) => {
const taken = await API.isUsernameTaken(s)
return taken ? 'Username is taken': true
}
}
Options
Sometimes it's practical to have some different default values when using for example react-native or some other framework where the default value
, onChange
and (e)=> e.target.value
do not apply.
Example: React Native (Method 1 - Global options)
Check the Expo Snack for a live preview
import * as React from 'react'
import { Text, SafeAreaView, TextInput } from 'react-native'
import { useForm } from 'formhero'
const initial = {
username: 'i am all lowercase',
}
const validators = {}
const options = {
setter: 'value', // This is not stricly necessarry as 'value' would already be the default.
getter: 'onChangeText',
extractor: text => text.toLowerCase(),
}
export default () => {
const { form, field } = useForm(initial, validators, options)
return (
<SafeAreaView>
<TextInput style={{ height: 40, borderColor: 'gray', borderWidth: 2 }} {...field('username')} />
<Text>{form.username}</Text>
</SafeAreaView>
)
}
Example: React Native (Method 2 - Local overwrite)
// ...
export default () => {
const { form, field } = useForm({
username: 'i am all lowercase',
})
return (
<SafeAreaView>
<TextInput
style={{ height: 40, borderColor: 'gray', borderWidth: 2 }}
{...field('username', {
setter: 'value', // This is not stricly necessarry as 'value' would already be the default.
getter: 'onChangeText',
extractor: text => text.toLowerCase(),
})}
/>
<Text>{form.username}</Text>
</SafeAreaView>
)
}
field
The field
object is used to bind the form state to the input.
Example: Simple
const { field } = useForm()
<input {...field('username')} />
Example: With custom options
All are optional.
const { field } = useForm()
<input {...field('username', {
getter: 'onChage',
setter: 'value',
extractor: (e) => e.target.value
})} />
Form
This is the form state that you can use when submitting the data
Example
const { form } = useForm(...);
// ...
<form onSubmit={()=> console.log(form)}>
// ...
</form>
Errors
This object contains the error messages if a field is not valid.
The error message can be specified by you, otherwise it will return Error in ${field}
Example
const { errors } = useForm(...)
//...
{errors.username}
{errors.password}
isValid
isValid
is a little simple helper that checks whether the error
object is clear or if there are errors left.
setField
The setField
function allows you to manually change and assign the state of a field. The type of the field must be the same as the initial type given in the constructor.
Example
const { form, setField } = useForm(...)
const resetUsername = () => {
setField('username', 'new value')
}
setForm
The setForm
function allows you to manually change and assign the state of the form. This can be usefull when you want to reset a field or the whole form. The input must have the same type as the initial state.
Example
const initial = {username: '', password: ''}
const { form, setForm } = useForm(initial, ...)
const resetForm = () => {
setForm(initial)
}
setErrors
The setErrors
function allows you to manually change and assign the state of the errors. This can be usefull when you want to set an error manually (e.g. sent from the server).
Example
const { form, setErrors } = useForm(...)
const setError = () => {
setErrors({username: 'Already taken'})
}
Thanks & Attributions
- Thanks for brendanmckenzie for suggesting to change
auto
tofield
.