npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-minimalistic-use-form

v2.0.0

Published

Minimalistic react hook for handling forms without much pain.

Downloads

17

Readme

version Software License TypeScript npm downloads

Table of contents

Minimalistic react hook for handling forms without much pain.

React-minimalistic-use-form provides minimalistic way to handle forms in react. It takes care of form state and validation. Validation is based on html5 form validation. It uses Constraint Validation API and validates form based on input validity. This library has just peer dependencies "react": ">=16.13.1", "react-dom": ">=16.13.1" and absolutely ZERO OTHER DEPENDENCIES, it's lightweight and powerful!

It provides ability to validate form fields on user input AND|OR on form submit. It automatically adds or removes error class name to input field if field is valid or not.
Form can be explicitly controlled by manually attaching event handlers or implicitly by combining useForm hook and <Form /> component where Form component will bind values and event handlers automatically for you!

Installation

  • NPM npm i react-minimalistic-use-form

  • YARN yarn add react-minimalistic-use-form

Features

  • Form state management
  • Native html5 form validation
  • Form validation on input or on submit
  • Automatically toggles error and "is-touched" input class names
  • Scroll to error
  • Very lightweight with no dependencies
  • Typescript support
  • Built-in validation debounce with auto cancellation for stale validations
  • Opt-in via plugins to add custom validator or custom scroll to error functionality

Current supported form fields

  • input
    • text
    • number
    • email
    • password
    • textarea
    • checkbox
    • radio
    • select
    • tel
    • date
    • search
    • url
    • color

Supported validation rules - built in Form validation

  • valid – Is true when the field passes validation.
  • valueMissing – Is true when the field is empty but required.
  • typeMismatch – Is true when the field type is email or url but the entered value is not the correct type.
  • tooShort – Is true when the field contains a minLength attribute and the entered value is shorter than that length.
  • tooLong – Is true when the field contains a maxLength attribute and the entered value is longer than that length.
  • patternMismatch – Is true when the field contains a pattern attribute and the entered value does not match the pattern.
  • badInput – Is true when the input type is number and the entered value is not a number.
  • stepMismatch – Is true when the field has a step attribute and the entered value does not adhere to the step values.
  • rangeOverflow – Is true when the field has a max attribute and the entered number value is greater than the max.
  • rangeUnderflow – Is true when the field has a min attribute and the entered number value is lower than the min.

For custom validation see Plugins - validator.


Example usage

EXPLICIT FORM CONTROL
  • import useForm hook
  • attach formRef to the form
  • attach event handlers (needed form handling iternal state and validation)
import React from 'react';
import { useForm } from 'react-minimalistic-use-form';

export const MyForm = () => {
    const {
        isFormValid, values, onChange, onBlur, onSubmit, errors, formRef
      } = useForm({ initialValues: { field1: 'foo', field2: 'bar'} });
    
    const submitForm = ({ event, values, errors, isFormValid }) => {
     event.preventDefault();
     /* do some logic here... */
    };

  return (
    <form onSubmit={onSubmit(submitForm)} noValidate ref={formRef}>
      <div>
        <label htmlFor="field1">Field1</label>
        <input id="field1" name="field1" type="email" required value={values.field1} onChange={onChange} onBlur={onBlur} />
        {errros.field1 && Object.values(errors.field1).map((error, index) => (
        <span key={index} className="text-error">
          {error}
          <br />
        </span>))}
      </div>
       
      <div>
        <label htmlFor="field2">Field2</label>
        <input id="field2" name="field2" type="text" minLength="5" required value={values.field2} onChange={onChange} onBlur={onBlur} />
        {errros.field2 && Object.values(errors.field2).map((error, index) => (
          <span key={index} className="text-error">
            {error}
            <br />
          </span>))}
      </div>

      <div>
        <button type="submit" disabled={isFormValid === false}>
          <span>Start!</span>
        </button>
      </div>
    </form>
  );
}
IMPLICIT FORM CONTROL

If you find adding onChange and onBlur event handlers painful and repetitive job, or you simply don't want to add any extra logic, it is possible to let useForm hook do that automatically for you by combining useForm and <Form /> component.

  • import useForm
  • import Form
  • just attach bindUseForm to Form
import React from 'react';
import { useForm, Form } from 'react-minimalistic-use-form';

export const MyForm = () => {
    const {
        isFormValid, onSubmit, errors, bindUseForm
      } = useForm({ initialValues: { field1: 'foo', field2: 'bar'} });
    
    const submitForm = ({ event, values, errors, isFormValid }) => {
     event.preventDefault();
     /* do some logic here... */
    };
    
    return (
        <Form onSubmit={onSubmit(submitForm)} noValidate bindUseForm={bindUseForm}>
          <div>
            <label htmlFor="field1">Field1</label>
            <input id="field1" name="field1" type="text" required />
            {errors.field1 && Object.values(errors.field1).map((error, index) => (
                <span key={index} className="text-error">
                  {error}
                  <br />
                </span>
             ))}
          </div>
           
           <div>
            <label htmlFor="field2">Field2</label>
            <input id="field2" name="field2" type="text" required minLength={4} />
            {errors.field2 && Object.values(errors.field2).map((error, index) => (
              <span key={index} className="text-error">
                {error}
                <br />
              </span>))}
          </div>
           
          <div>
            <button type="submit" disabled={isFormValid === false}>
              <span>Start!</span>
            </button>
          </div>
         
        </Form>
    );
}

Form component needs bindUseForm prop from useForm hook otherwise an Error will be thrown. Form will automatically bind input values and onChange, onBlur eventHandlers that will handle form validation properly.

NOTE: Form input elements must have id and name attributes set, otherwise Form will not consider it as an input field, hence it won't attach needed event handlers.

Either using just useForm hook or in a combination with Form component, useForm hook will handle validation automatically for you. Optionally validateOnInput (boolean) or validateOnSubmit (boolean) can be configured.

In first case, on user input, useForm will automatically validate that field, update errors object properly and it will toggle error className to input field. To provide the best user experience once input field is blurred, useForm onBlur eventHandler will set className is-touched (default value can be configured) and it will trigger input validation. If field has validity: false an error className has-error (default value, can be configured) will be attached to input field. As soon as field validity is valid, error class is removed from the field.

errors object contains all form field errors in format:

errors: {
  [fieldName]: {
    [validityName]: 'Error message',
    [otherValidityName]: 'Another error message'
  }
}

Validity names are native html5 ValidityState interface properties. It's up to consumer how error messages will be displayed/styled/translated...

Custom controlled inputs

It's fully possible to have custom controlled inputs either by just using useForm hook or with <Form /> component as well. Only difference is that useForm hook without Form component requires onChange and onBlur handlers to be called in order to track form internal state and validation, where Form component automatically binds those so custom controlled inputs don't need to attach them additionally.

Here are both examples.

import React, { useState} from 'react';
import { useForm, Form } from 'react-minimalistic-use-form';

export const MyForm = () => {
  const {
    isFormValid, onChange, onBlur, onSubmit, formRef
  } = useForm();
  
  const [controlledField1, setControlledField1] = useState("field1");
  
  const _onChange = event => {
    setControlledField1(event.target.value);
    onChange(event); // useForm onChange needs to be called!
  };

  const _onBlur = event => {
    /* some logic goes here */
    onBlur(event); // useForm onBlur needs to be called!
  };

  const submitForm = ({ event, values, errors, isFormValid }) => {
    event.preventDefault();
    /* do some logic here... */
  };
    
  return (
    <form onSubmit={onSubmit(submitForm)} noValidate ref={formRef}>
      <div>
        <label htmlFor="field1">Field1</label>
          <input id="field1" name="field1" type="email" value={controlledField1} onChange={_onChange} onBlur={_onBlur} />
      </div>
           
      <div>
        <button type="submit" disabled={isFormValid === false}>
          <span>Start!</span>
        </button>
      </div>
    </form>
  );
}
import React, { useState} from 'react';
import { useForm, Form } from 'react-minimalistic-use-form';

export const MyForm = () => {
const {
    isFormValid, onSubmit, bindUseForm
  } = useForm();
  
  const [controlledField1, setControlledField1] = useState("field1");
  const _onChange = event => {
    setControlledField1(event.target.value);
  };

const submitForm = ({ event, values, errors, isFormValid }) => {
 event.preventDefault();
 /* do some logic here... */
};


return (
    <Form onSubmit={onSubmit(submitForm)} noValidate bindUseForm={bindUseForm}>
      <div className="col-12 mt-3">
        <label htmlFor="field1" className="m-0 mb-1 p-0">Field1</label>
        <input id="field1" name="field1" type="email" value={controlledField1} onChange={_onChange} />
      </div>
       
      <div className="col-12">
        <button type="submit" className="mt-3 mb-0" disabled={isFormValid === false}>
          <span>Start!</span>
        </button>
      </div>
    </Form>
  );
}

API

useForm

useForm accepts configuration object with following options:

| property | description | type | default | |-------------------------|--------------------------------------------------------|--- |--------------| | initialValues | Form initial values | object | {} | | errorClassName | Input field error class name | string | "has-error" | | touchedClassName | Input field "touched" class name | string | "is-touched" | | scrollToError | Scroll to form input field that has an error. | boolean | false | | scrollToErrorOptions | Scroll to error options | object | undefined | | validateOnInput | Validate form on user input. | boolean | true | | validateOnSubmit | Validate form on submit. | boolean | false | | validateOnMount | Validate form on mount. | boolean | false | | debounceValidation | Debounce input validation. | boolean | false | | debounceTime | Debounce input validation timeout in milliseconds. | boolean | 300 | | plugins | Plugins to opt-in with custom logic. | object | {} |

Scroll to Error
  • scrollToError - If enabled useForm will scroll to element in case input has an error. It will try to find input label to scroll to or if no label found it will scroll to input field. By default useForm is using Element.ScrollIntoView() with provided scrollToErrorOptions;

  • scrollToErrorOptions - options to be passed in as an argument to Element.ScrollIntoView().

  • What options are supported and how scrollIntoView works, which browsers are supported etc. check out official documentation on MDN - Element.ScrollIntoView()

Plugins

Use Form offers possibility to opt-in via plugins prop and change default useForm capabilities. Currently supported plugins:

scrollToError
  • scrollToError - scrolltoError plugin is a function that will be called on input field error. useForm calls a scrollToError plugin function with one argument, the DOM label element (if one found) or input element itself. If scrollToError plugin is provided the default Element.ScrollIntoView() is overridden and hence ignored.
validator
  • validator - validator plugin is a function that will be called upon onChange event.

  • function will be called with object {name, value, values, target} where name is the name of the current input field, value is the value of the current field, values is an object with all form field values and target is the input DOM element.

  • validator function should return an object with errors in format:

{
  fieldName: {
    errorKey: 'Error message',
    anotherErrorKey: 'Another Error message'  
  }
}

Example:

const validator = ({name, value, values }) => {
  const errors = {};

  if ((name === 'password_confirm' && value !== values.password) || (name === 'password' && value !== values.password_confirm)) {
    errors.password_confirm = {
      passwordMismatch: 'Passwords do not match!',
    };
  }

  return errors;
};
useForm in return provides:
  • resetForm - function - resets form to initial state.
  • onChange - function - event handler needed for handling validation and input state.
  • onBlur - function - event handler needed for handling form validation
  • onSubmit - function - Curry function that accepts callback as an argument. It returns an object with { event, errors, values, isFormValid }
  • validateForm - function - validates form and returns isFormValid (boolean)
  • isFormValid - boolean - Boolean describing form validity.
  • formRef - react useRef instance - *required to be attached to form
  • values - object - form values
  • errors - object - form errors
  • bindUseForm - object - *required to be attached to <Form /> to automatically bind formRef and event handlers
  • isSubmitting - boolean - Boolean flag describing is form being in submission state
  • setIsSubmitting - function - Function to Toggle isSubmitting state

NOTE: isFormValid onMount will be checked only against native html validation, input validity. You can choose how to handle initial isFormValid state:

  • by combining validateOnInput and manually triggering validateForm once your component is mounted
  • by just validating on submit
  • by passing validateOnMount which will check native html validation + it will call custom validator if provided
Form Submission
  1. UseForm will set isSubmitting to true when form is submitted.
  2. If validateOnSubmit is true it will run validation and update isFormValid and errors.
  3. It Call your registered submission handler i.e. onSubmit({ event, isFormValid, errors, values });
  4. You have to call setIsSubmitting(false).

Form

Form accepts all html5 form attributes along with one required:

| property | description | type | |--- |--- |--- | |bindUseForm | Object - contains formRef and eventHandlers | object *required |