
Security News
Deno 2.6 + Socket: Supply Chain Defense In Your CLI
Deno 2.6 introduces deno audit with a new --socket flag that plugs directly into Socket to bring supply chain security checks into the Deno CLI.
react-form-ali
Advanced tools
A fast, lightweight, opinionated table and datagrid built on React-Form
React Form is a lightweight framework and utility for building powerful forms in React applications.
$ npm install react-form-ali
What does React-Form look like? This is the shortest and most concise example we could think of. Looking for more detail? Dive deep with the Annotated Demo Example
import React from 'react'
import { Form, Text } from 'react-form'
const MyForm = Form({
validate: ({ name }) => {
return {
name: !name ? 'A name is required' : undefined
}
},
})(({submitForm}) => {
return (
<form onSubmit={submitForm}>
<Text field='name' />
<button type='submit'>Submit</button>
</form>
)
})
export default () => {
return (
<MyForm
onSubmit={(values) => {
console.log('Success!', values)
}}
/>
)
}
This is an annotated example of the demo, demonstrating a majority of React-Form's features.
import React from 'react'
import { Form, Text, Select, Textarea, Checkbox, Radio, NestedForm, FormError } from 'react-form'
// To create a new form, simply call `Form(config)(component)`
const MyForm = Form({
// This is our config for the form. Think of it as the default props for your Form :)
// Let's give the form some hard-coded default values
defaultValues: {
friends: []
},
// Validating your form is super easy, just use the `validate` life-cycle method
validate: values => {
const { name, hobby, status, friends, address } = values
return {
name: !name ? 'A name is required' : undefined,
hobby: (hobby && hobby.length < 5) ? 'Your hobby must be at least 5 characters long' : false,
status: !status ? 'A status is required' : null,
friends: (!friends || !friends.length) ? 'You need at least one friend!' : friends.map(friend => {
const { name, relationship } = friend
return {
name: !name ? 'A name is required' : undefined,
relationship: !relationship ? 'A relationship is required' : undefined
}
}),
address: !address ? 'A valid address is required' : 0
}
},
// `onValidationFail` is another handy form life-cycle method
onValidationFail () {
window.alert('There is something wrong with your form! Please check for any required values and try again :)')
}
})(({ values, submitForm, addValue, removeValue, getError, setValue }) => {
// This is a stateless component, but you can use any valid react component to render your form.
// Forms also supply plenty of useful props for your components to utilize. See the docs for a complete list.
return (
// When the form is submitted, call the `sumbitForm` callback prop
<form onSubmit={submitForm}>
<div>
<h6>Full Name</h6>
<Text // This is the built-in Text formInput
field='name' // field is a string version of the field location
placeholder='Your name' // all other props are sent through to the underlying component, in this case an <input />
onChange={(value) => { // it needs to call setState to apply the text field changes
// capitalize first letter
if (value.length > 0) {
setValue('name', value.charAt(0).toUpperCase() + value.slice(1))
} else {
setValue('name', value)
}
}}
/>
</div>
<div>
<h6>Relationship Status</h6>
<Select // This is the built-in Select formInput
field='status'
options={[{ // You can ship it some options like usual
label: 'Single',
value: 'single'
}, {
label: 'In a Relationship',
value: 'relationship'
}, {
label: 'It\'s Complicated',
value: 'complicated'
}]}
/>
</div>
<div>
<h6>Short Bio</h6>
<Textarea // This is the built-in Textarea formInput
field='bio'
placeholder='Short Bio'
/>
</div>
{/* Arrays in forms are super easy to handle */}
<h6>Friends</h6>
{/* This is a custom form error for the root of the friends list (see validation function) */}
<FormError field='friends' />
<div className='nested'>
{!values.friends.length ? (
<em>No friends have been added yet</em>
) : values.friends.map((friends, i) => ( // Loop over the values however you'd like
<div key={i}>
<div>
<h6>Full Name</h6>
<Text
field={['friends', i, 'name']} // You can easily pass an array-style field path. Perfect for passing down as props or nested values
placeholder='Friend Name'
/>
</div>
<div>
<h6>Relationship</h6>
<Select
field={`friends.${i}.relationship`} // If you don't like arrays, you can also use a string template
options={[{
label: 'Friend',
value: 'friend'
}, {
label: 'Acquaintance',
value: 'acquaintance'
}, {
label: 'Colleague',
value: 'colleague'
}]}
/>
</div>
<button // This button will remove this friend from the `friends` field
type='button'
onClick={() => removeValue('friends', i)} // `removeValue` takes a field location for an array, and the index for the item to remove
>
Remove Friend
</button>
</div>
))}
</div>
<div>
<button // This button will add a new blank friend item to the `friends` field
type='button'
onClick={() => addValue('friends', {})} // `addValue` takes an array-like field, and the value to add
>
Add Friend
</button>
</div>
<div>
<h6>Address</h6>
{/* An address has a couple of parts to it, and will probably have its own validation function. */}
{/* Let's make it reusable by using a nested form */}
<NestedForm
form={AddressForm} // This is just another form that we built below
field='address' // The results of this nested form will be set to this field value on this form.
/>
</div>
<div>
<label>
<Checkbox // This is the built-in checkbox formInput
field='createAccount'
/>
<span>Create Account?</span>
</label>
</div>
<div>
<h6>Notify me via</h6>
<radiogroup>
<label>
<Radio // This is the built-in radio formInput
field='notificationType'
value='email' // This is the value the field will be set to when this radio button is active
/>
<span>Email</span>
</label>
<label>
<Radio
field='notificationType'
value='text'
/>
<span>Text</span>
</label>
<label>
<Radio
field='notificationType'
value='phone'
/>
<span>Phone</span>
</label>
</radiogroup>
</div>
<br />
<br />
{/* // Since this is the parent form, let's put a submit button in there ;) */}
{/* // You can submit your form however you want, as long as you call the `submitForm` callback */}
<button>
Submit
</button>
</form>
)
})
// This is our reusable address form
const AddressForm = Form({
// It can have its own validation function!
validate: values => {
return {
street: !values.street ? 'A street is required' : undefined,
city: !values.city ? 'A city is required' : undefined,
state: !values.state ? 'A state is required' : undefined
}
}
})(() => {
return (
<div>
<Text
field='street'
placeholder='Street'
/>
<br />
<Text
field='city'
placeholder='City'
/>
<br />
<Text
field='state'
placeholder='State'
/>
</div>
)
})
export default () => {
return (
<div>
<div className='table-wrap'>
<MyForm
onSubmit={(values) => {
window.alert(JSON.stringify(values, null, 2))
}}
// For more available props, see the docs!
/>
</div>
</div>
)
}
Creating custom form inputs is extremely simple. This is a quick example of how to wrap the React-Select component:
// formReactSelect.js
import React from 'react'
import { FormInput } from 'react-form'
import Select from 'react-select'
export default ({field, ...rest}) => {
return (
<FormInput field={field}> // Use FormInput with a fieldName to get the field's api
// FormInput's only child should be a function that provides you the field api and returns valid jsx or a react component
{({ setValue, getValue, setTouched }) => {
return (
<Select
{...rest} // Send the rest of your props to React-Select
value={getValue()} // Set the value to the forms value
onChange={val => setValue(val)} // On Change, update the form value
onBlur={() => setTouched()} // And the same goes for touched
/>
)
}}
</FormInput>
)
}
// Now you can use it in a form!
import React from 'react'
import FormReactSelect from './formReactSelect'
Form()(() => {
return (
<FormReactSelect
field='my.field'
clearable={false}
options={[...]}
/>
)
})
Form(defaultPropsAndLifecycleMethods)(component)Example
import { Form } from 'react-form'
// Create a new form by passing `Form` any default props and/or lifecycle methods
const myForm = Form({
validate () {...},
})(validReactComponent)) // Then pass in any valid react component, component class or stateless component
The form lifecycle is what makes React-Form tick, so naturally you can configure just about anything in react-form to your needs through these lifecycle methods.
You can define form props and lifecycle methods at 3 different levels:
FormDefaultProps (See {FormDefaultProps})defaultProps to FormHere is a list of all available properties and lifecycle methods that React-Form uses:
Form({
defaultValues: {
name: 'Tanner Linsley'
hobby: 'javascript'
}
})(component)
loadState is called. If a saved form state object is returned, it will hydrate the form state from this object.Form({
preValidate: (values) => {
values.hobby = values.hobby.substring(0, 6) // Constantly scrub the hobby field to never be more than 6 characters long
return values
}
})(component)
validate returns any errors, setAllTouched(true) will automatically be called on the form. Likewise, if the form has been marked as globally dirty, and no errors are returned, setAllTouched(false) will automatically clear the global dirty stateForm({
validate: ({name, password}) => {
return {
name: !name ? 'A name is required' : null,
password: (!password || password.length < 6) ? 'A password of 6 or more characters is required' : null
}
}
})(component)
values changeinitial is set to true, this indicates that the component just mounted and is firing onChange for the first time (this is utilized by nested forms)state is changed.onSubmit method.Form({
preSubmit: (values) => {
values.hobby = values.hobby.toLowerCase() // Scrub the hobby field to be lowercase on submit
return values
}
})(component)
submitForm, this method will be called with the values of the parent form.// Per Instance (usually this way)
const example = (
<MyForm
onSubmit={(values) => {
console.log('Form Submitted with these values:', values)
}}
/>
)
// Per Form
Form({
onSubmit: (values) => {
console.log('Form Submitted with these values:', values)
}
})(component)
submitForm, this method will be called.Form({
postSubmit: (values) => {
console.log('Success!', values)
}
})(component)
defaultProps will function as hardcoded defaultProps. They will be available on the componentused to render the form unless overridden by a prop passed tot he instanceAll of the following props are available on the component used to render your form
Note: If a prop of the same name is passed to the form instance, it will override these props below.
Form()(
({values}) => {
console.log(values)
// {
// name: 'Tanner Linsley',
// hobby: 'Javascript',
// nestedForm: {
// notes: 'These are some notes from a nested form'
// }
// }
}
)
FormInput or using the FieldError component.validate lifecycle methodnullForm()(
({errors}) => {
console.log(errors)
// {
// name: 'Name is required and must be at least 5 characters',
// hobby: 'Required',
// nestedForm: 'Requires some valid nested fields' // See "nestedErrors" section
// }
}
)
nestedErrors is an object map indicating any nested forms that did not pass their own validationFormInput or using the FieldError component.nestedErrors field will be set to true.{}Form()(
({nestedErrors}) => {
console.log(nestedErrors)
// {
// nestedForm: true // there must be an error in the form located at the "nestedForm" field
// }
}
)
setValue() or setTouched(), its corresponding field location in this object is marked as true.FormInput or using the FieldError component.{}Form()(
({touched}) => {
console.log(touched)
// {
// touched: { myField: true } // the `myField` field has been touched
// }
}
)
field to value. Usually this functionality is contained in an InputField of sorts, but it is still available on the form itself in its generic form.field can be a string or array property location eg.
my.field.name == ['my', 'field', 'name']my.fields[3] == ['my', 'fields', 3][['my', 'fields'], [5], 'stuff'] == my.fields[5].stuffnoTouch is true, the touched state of the field won't change.Form()(
({setValue}) => {
return (
<button onClick={() => setValue('some.field', true)}>
Set Some Field to TRUE
</button>
)
}
)
field. Usually this functionality is contained in an InputField of sorts, but it is still available on the form itself in its generic form.field can be a string or array property location eg.
my.field.name == ['my', 'field', 'name']my.fields[3] == ['my', 'fields', 3][['my', 'fields'], [5], 'stuff'] == my.fields[5].stufffallback value which will be used if the field does not exist or if its value === undefinedForm()(
({getValue}) => {
return (
<span>Current Value: {getValue('my.field')}</span>
)
}
)
field in nestedErrors to value to indicate that a nested form did or did not not pass its own validation.validate lifecycle method will be set to undefined.validate lifecycle method.NestedForm componentfield. Usually this functionality is contained in an InputField of sorts, but it is still available on the form itself in its generic form.field can be a string or array property location eg.
my.field.name == ['my', 'field', 'name']my.fields[3] == ['my', 'fields', 3][['my', 'fields'], [5], 'stuff'] == my.fields[5].stuffForm()(
({getError}) => {
return (
<span>Current Error: {getError('my.field')}</span>
)
}
)
field in the touched state to value (which defaults to true). Usually this functionality is contained in an InputField of sorts, but it is still available on the form itself in its generic form.field can be a string or array property location eg.
my.field.name == ['my', 'field', 'name']my.fields[3] == ['my', 'fields', 3][['my', 'fields'], [5], 'stuff'] == my.fields[5].stuffForm()(
({setTouched}) => {
return (
<button onClick={() => setTouched('some.field', true)}>
Set some fields touched value to TRUE
</button>
)
}
)
field. Usually this functionality is contained in an InputField of sorts, but it is still available on the form itself in its generic form.field can be a string or array property location eg.
my.field.name == ['my', 'field', 'name']my.fields[3] == ['my', 'fields', 3][['my', 'fields'], [5], 'stuff'] == my.fields[5].stuffForm()(
({getTouched}) => {
return (
<span>Current Touched: {getTouched('my.field')}</span>
)
}
)
value into an array-like field as a new value.field can be a string or array property location eg.
my.field.name == ['my', 'field', 'name']my.fields[3] == ['my', 'fields', 3][['my', 'fields'], [5], 'stuff'] == my.fields[5].stuffForm()(
({addField}) => {
return (
<button onClick={() => addField('todos', {})}>
Add Todo
</button>
)
}
)
field.field can be a string or array property location eg.
my.field.name == ['my', 'field', 'name']my.fields[3] == ['my', 'fields', 3][['my', 'fields'], [5], 'stuff'] == my.fields[5].stuffForm()(
({removeField}) => {
return (
<div>
{todos.map((todo, i) => {
return (
<button onClick={() => removeField('todos', i)}>
Remove Todo
</button>
)
})}
</div>
)
}
)
field.field can be a string or array property location eg.
my.field.name == ['my', 'field', 'name']my.fields[3] == ['my', 'fields', 3][['my', 'fields'], [5], 'stuff'] == my.fields[5].stuffForm()(
({swapValues}) => {
return (
<div>
{todos.map((todo, i) => {
return (
<button onClick={() => swapValues('todos', i, i - 1)}>
Move Up
</button>
)
})}
</div>
)
}
)
dirty state to !!value (which defaults to true). If true, its value will override any value retrieved using getTouched.submitForm lifecycle method when a forms validation is failedForm()(
({setAllTouched}) => {
return (
<button onClick={setAllTouched}>
Touch / Dirty the entire form // innuendo? hmm....
</button>
)
}
)
preValidate(values, state, props) filter your values before they are validatedvalidate(values, state, props) validate your formonValidationFail(state, props) handle failed validation (if applicable)preSubmit(values, state, props) filter your values before they are successfully submittedonSubmit(values, state, props) handle the submissionpostSubmit(values, state, props) handle after a successful submissionconst MyForm = Form()(
({submitForm}) => {
return (
<form onSubmit={submitForm}>
<button type='submit'>Submit Form</button>
</form>
)
}
)
const usageExample = () => {
return (
<MyForm
onSubmit={(values, state, props) => {
console.log(values)
}}
/>
)
}
import { FormDefaultProps } from 'react-form'
Object.assign(FormDefaultProps, {
onValidationFail: () => { console.log('uh oh...') }
})
FormInput must be a function that returns valid JSX. This function is passed one parameter, the form api object.field prop is passed, every API method will be auto-bound to use that field. Otherwise, they operate at the form-level as usual.showErrors prop is set to false, errors will be hiddenerrorBefore prop is set to true, any error will be shown before the component, instead of afterisForm props is set to true, the field error will only be shown if the parent form has been unsuccessfully submitted. This is normally only used for NestedForm components to avoid unnecessary or duplicate error messages.Example - A simple wrapper for React Select
import { FormInput } from 'react-form'
import ReactSelect from 'react-select'
export default ({field, ...rest}) => {
return (
<FormInput field={field}>
{({ setValue, getValue, setTouched }) => {
return (
<ReactSelect
{...rest}
value={getValue()}
onChange={val => setValue(val)}
onBlur={() => setTouched()}
/>
)
}}
</FormInput>
)
}
Example
import { FormError } from 'react-form'
const example = (
<FormError field='my.field' />
)
###{ AddErrors }
FormField must be a function that returns valid JSX. This function is passed one parameter, the form api object.field prop is passed, every API method will be auto-bound to use that field. Otherwise, they operate at the form-level as usual.Example
import { FormField } from 'react-form'
function customInput ({field, ...rest}) {
return (
<FormField field={field}>
{({ setValue, getValue, setTouched }) => {
return (
<input
value={getValue()}
onChange={e => setValue(e.target.value)}
onBlur={() => setTouched()}
/>
)
}}
</FormField>
)
}
FormInput component.field prop to be passednoTouch to avoid validation while the value is changingExample
import { Text, Select, Checkbox, Textarea, Radio } from 'react-form'
const example = (
<div>
<Text
field='name'
placeholder='Full name'
/>
<Select
placeholder='choose status...'
field='employed'
options={[{
label: 'Employed',
values: true
}, {
label: 'Unemployed',
value: false
}]}
/>
<Select
placeholder='choose favorite sports...'
field='sports'
options={[{
label: 'Baseball',
values: 'baseball'
}, {
label: 'Soccer',
value: 'soccer'
}]}
multiple
/>
<Checkbox
field='createAccount'
/>
<Textarea
field='notes'
placeholder='Notes'
/>
<radiogroup>
<Radio
field='notificationType'
value='email'
/>
<Radio
field='notificationType'
value='text'
/>
<Radio
field='notificationType'
value='phone'
/>
</radiogroup>
</div>
)
object to their assigned field on their parent form.undefined to their parent's validation function in place of the nested form's values. For instance, if a nested form using the field myNestedForm has an error, the parent validation function might look like this: validate ({name, hobby, myNestedForm}) {
return {
// normal validation...
myNestedForm: !myNestedForm ? 'Name Required' : undefined,
}
}
<Form /> elements (which would be invalid HTML).onValidationFailpreSubmitonSubmitTo suggest a feature, create an issue if it does not already exist. If you would like to help develop a suggested feature follow these steps:
npm installnpm watchsrc/ directoryIf you would like to preview your changes, you can link and utilize the example like so:
npm linkcd examplenpm installnpm link react-formnpm watchsrc/screens/index.js if neededlocalhost:8000Also you may use react-storybooks to view changes. Feel free to add new storybooks if they don't exist yet.
npm run storybooklocalhost:8085
##Credits This is a fork from https://github.com/tannerlinsley/react-form with some minor improvements
FAQs
A fast, lightweight, opinionated table and datagrid built on React-Form
We found that react-form-ali demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Deno 2.6 introduces deno audit with a new --socket flag that plugs directly into Socket to bring supply chain security checks into the Deno CLI.

Security News
New DoS and source code exposure bugs in React Server Components and Next.js: what’s affected and how to update safely.

Security News
Socket CEO Feross Aboukhadijeh joins Software Engineering Daily to discuss modern software supply chain attacks and rising AI-driven security risks.