react-formulize

1.2.1 • Public • Published

react-formulize Build Status Coverage Status

React-formulize is a simple form validation library for React.js which wires up custom, controlled inputs through a declarative API. The library strives to be minimal, and as such, does most component communication implicity. The end result is a legible form which clearly states the rules of its behavior.

Table of Contents

  1. Installation
  2. Usage
  3. Form Component
  4. Field Component
  5. Tests
  6. Contributing
  7. License
  8. Release History

Installation

npm install react-formulize --save

Usage

React-formulize can be used to both quickly compose forms or add validation to existing input components.

Rules to follow:

  1. A Form component can wrap (nested JSX) a set of Field components or input elements (or fragments containing them) and automatically manage the state of them. All Fields and inputs must have name props assigned to them.
  2. A Field component can wrap (nested JSX) an input element, a fragment containing an input, or a custom component flagged with a props.input=true, and control its underlying state automatically.
  3. Pass validator props to the Field components. A Field component will keep track of its own validity.
  4. Pass an onSubmit handler to Form in order to interact with the submission event. The callback will be passed a clone of the Form's state.
  5. Pass valid and pristine props to any nested child components in either a Form or Field component. These components will receive information about the Form's status in the format of ${fieldName}_${statusType} (e.g. name_valid & email_pristine).

Example: Composing A New Form With Custom Input Component(s)

  import React from 'react';
  import { Form, Field } from 'react-formulize';
  import { AgePickerComponent } from './components/agePicker';
  
  const onSubmit = formState => console.log(formState);
  
  export default function (props) { 
    return (
      <Form onSubmit={onSubmit}>
        <Field name="name_field" length={[3, 24]} />
        <Field name="age_field" required min="18" max="150">
          <AgePickerComponent input />
        </Field>
        <Field name="email_field" required email debounce="300">
          <label>
            Email: <input />
          </label>
          <span>Email Address must use a '.edu' domain!</span>
        </Field>
        <button type="submit" />
      </Form>
     );
  } 

Example: Adding Validation To An Existing Form Input

  import React from 'react';
  import { Field } from 'react-formulize';
  
  export class RegistrationForm extends React.Component { 
    constructor(props) {
      super(props);
      this.state = {
        'name': { value: '' },
        'email': { value: '' },
        'age': { value: '' },
      };
 
      this.onChange = this.onChange.bind(this);
    }
    
    onSubmit(e, formState) {
      e.preventDefault();
      console.log(formState);
    }
 
    onChange(e) {
      this.setState({ [e.target.name]: e.target.value });
    }
    
    render() {
      return (
        <form onSubmit={(e) => this.onSubmit(e, { ...this.state })}>
          <div>
            <input type="text" name="name" onChange={this.onChange}/>  
            
            <Field name="email" type="email" value={this.state.age} onChange={this.onChange} length={[6, 16]} email>
              <label>
                // The input is controlled! `Field` passes `name`, `value`, `type`, and `onChange` props for you!
                Enter Email: <input />
              </label>
              <span>Email Address must use a '.edu' domain!</span>
            </Field>
            
          </div>
          <button type="submit" />
        </form>
       );
     }
  } 

Form Component

Description

The Form component is a stateful higher-order-component which wraps presentational form components consisting of arbitrary input fields. Simply import the Form component and nest your custom components inside the Form tag.

The Form component will behave as follows with respect to its children:

  1. Any Field tag will be passed the state associated with the Field's name (Form.state[child.props.name]).
  2. Any component with a valid prop will be passed props stating the validity for all Fields in the Form (e.g. name_valid).
  3. Any component with a pristine prop will be passed a props stating the pristine state for all Fields in the Form (e.g. email_pristine).
  4. Any other component or element will be rendered with the props it would otherwise be passed.
  5. Upon submission, Form will pass its onSubmit callback a clone of its current state.

Note: The Form component should be passed an onSubmit handler if you want to interact with the submission event!

Props

props.onSubmit = onSubmitHandler(event, formState)

@param {Function} onSubmitHandler - A function used to interact with form submission.

This property will be invoked on a form submission event and passed the event and the event and current state.

Methods

instance.reset()

@description - Resets the Form instance by reinstating the default state. Does not unmount the instance.

The Form instance must be captured in a reference in order to be able to later invoke its reset method. This means that:

  1. A ref function must be passed to Form in order to receive the class component reference.
  2. Form must be used within a class component to enable the ref callback being invoked.
import React from 'react';
import { Form, Field } from 'react-formulize';
 
export default class extends React.Component {
  constructor() {
    this.updateValue = this.updateValue.bind(this);
    this.registerForm = this.registerForm.bind(this);
    this.resetForm = this.resetForm.bind(this);
  }
 
  addFormRef(form) {
    this.form = form;
  }
 
  updateValue(field, data) {
    this.setState({ [field]: data });
  }
 
  onSubmit(state) {
    console.log('SUBMITTING >>>', state);
  }
 
  resetForm(e) {
    e.preventDefault();
    this.form.reset(); // Instance method on `Form` component!
  }
 
  render() {
    return (
      <Form onSubmit={this.onSubmit} ref={this.addFormRef}>
        <Field name="name" length={[6, 20]} alpha />
        <Field name="email" email required />
        <Field name="age" type="number" min="18" max="100" />
        <button type="submit">Submit</button>
        <button onClick={this.reset}>Reset</button>
      </Form>
    );
  }
}

Field Component

Description

The Field component is a stateful, higher-order component which wraps a given presentational input component (or creates a default one). Input elements should be nested inside of Field tag. Each Field component will maintain its child's input element's value (state.value {String, Number}), validity(state.valid{Boolean}), and pristine state (state.pristine {Boolean}), as well as provide an onChange handler passed down through props.onChange.

The Field component will behave as follows with respect to its children:

  1. If no components are nested in a Field component, a default label and input element will be used.
  2. Any input tag will be passed name, type, value, and onChange props.
  3. Any component with an input flag (props.input = true) that is nested in a Field will be passed all of the relevant input props.
  4. If multiple input tags are nested in a single Field, they would all share a single state (not recommended).
  5. Any component with a valid prop will be passed a prop stating the Field's validity (e.g. name_valid).
  6. Any component with a pristine prop will be passed a prop stating the Field's pristine state (e.g. email_pristine).

Note: Only one input element should be nested inside of a Field tag (see #4 above).

Props

props.name = name

@param {String} [name=''] - The name of the wrapped input component.

The name of the wrapped input component. If no custom input component is passed in (via props.Input), then a label element will be created around the input and the input will be named, both with this value.

props.value = value

@param {String} [value=''] - The value of the wrapped input component.

This property is used to control the value of the wrapped input component. If set on the field, this value will be used everytime it is detected as a new (changed) value. This is useful in cases where you need to programmatically populate the field's value (but still allow the input to be edited).

props.type = type

@param {String} [type='text'] - The input type of the wrapped input element.

The input type for the wrapped input element. Defaults to text.

Note: When number input is desired, it is preferred to use 'text' inputs with a number validator if it is expected that the user will enter +, -, or e characters. See https://github.com/facebook/react/issues/1549.

props[validator] = [validator]

@param {?} [validator=?] - Optional. One or more validators to apply to the Field's state.

The Field component accepts different validators as props. See the Validators section for full list of validators to pass as props.

props.onChange = onChangeHandler

@param {Function} onChangeHandler - A function used to update (control) the state of the input element.

This property will be invoked on a change event in a wrapped input element (unless a custom input element is provided, then this function will be passed down to the custom component through props.onChange).

Note: You do not have to write this function if the Field component is nested inside of a Form component.

props.onFocus = onFocusHandler

@param {Function} onFocusHandler - A function to invoke upon input focus.

This property will be invoked on a focus event in the wrapped input element.

props.onBlur = onBlurHandler

@param {Function} onBlurHandler - A function to invoke upon input blur.

This property will be invoked on a blur event in the wrapped input element.

Validators

There are also a handful of different validators and properties (debounce, length, etc.) that can be attached to the field component. This is done by declaring the validators as props on the Field component. See below for the list of validators.

props.debounce = duration

@param {Number} duration - An amount to debounce props.onChange invocation.

This property adds a debounce to the input element broadcasting its state change to the Field component.

props.required = required

@param {Boolean} required - Toggles validation for a non-empty input.

This validates that the input is not empty.

props.length = [minLength, maxLength]

@param {Number} minLength - Validates component for mininum string input length. @param {Number} [maxLength] - Optional. Validates component for maximum string input length.

This validates that the string input is of a certain length. If maxLength is omitted, minLength will be interpreted as maxLength. As such, omitting maxLength allows the passed in value to be a single number (of type Number or String).

props.email = emailExpression

@param {RegularExpression} [emailExpression] - Optional. RegEx to validate email inputs against.

This validates that the string input matches either the default or provided regular expression.

props.match = valueToMatch

@param {*} valueToMatch - A value to validate the input's value against. If passed a function, function will be invoked.

This validates that the input matches the value provided. If a function is passed, it will be invoked and its result used to compare with the value.

props.alpha = alphaValidation

@param {Boolean} [alphaValidation=true] Optional. Will toggle validation for only alphabet and space characters.

This validates that the string input is comprised only of english alphabet characters and space characters.

props.number = numericValidation

@param {Boolean} [numericValidation=true] Optional. Will toggle validation for only numeric characters.

This validates that the string or number input is comprised only of numeric characters. This will allow appropriately placed +, -, e, and . characters.

props.max = maxValue

@param {Number} maxValue - Validates an input field to be less than or equal to the maxValue.

This validates that the provided number (or string-coerced-to-number) is less than or equal to the provided maxValue.

props.min = minValue

@param {Number} minValue - Validates an input field to be greater than or equal to the minValue.

This validates that the provided number (or string-coerced-to-number) is greater than or equal to the provided minValue.

props.custom = validatingFn

@param {Function} validatingFn - A custom validating function which returns a validity boolean.

The passed-in validating function, invoked once per Field update with the current component value, should return true for valid values and false for invalid values.

Tests

Run npm run pack for full linting, transpiling, and testing.
Run npm test for just tests.

Contributing

Implement any changes in the src/ files and use npm run build to build the dist/ directory.

Please use the AirBNB style guide for consistency. Add unit tests for any new or changed functionality. Lint and test your code. Thanks!!

License

MIT (See license.txt)

Release History

Package Sidebar

Install

npm i react-formulize

Weekly Downloads

2

Version

1.2.1

License

MIT

Last publish

Collaborators

  • clocasto