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

@tswaters/react-form-validation

v2.0.0

Published

React form validation components

Downloads

8

Readme

React Form Validation

The goal of this library is to implement the Constraint Validation API in React while not getting in your way to do it.

Of the existing react form libraries, the use of the constraint validation api is woefully inadequate. Using this API properly is important for accessibility - you need to let the user agent know what is going on.

usage

You can import the Form and Input/Select/TextArea exports from this library.

These are wrappers around <form/> and <input/select/textarea> elements. Any additional props you provide to these elements will be passed down to the underlying form/input/select/textarea element. If you need to, you can also access the underlying element by passing a ref.

Input elements must be children of a Form element. Under the covers, this library uses context to keep track of all fields on the form and will validate all of them if the form is submitted.

A Validator component is also provided which attempts to make using the api a bit easier. This is a container element that uses a render prop which is called with ({ error, valid, invalid, validated }). This routine recursively traverses any provided props to replace input/select/textarea elements with the exports from this library, so it will duplicate any work already done up to that point.

api

Form

import { Form } from '@tswaters/react-form-validation'
const example = () => {
  return <Form />
}
  • ref - you can pass a ref to get a reference to the underlying <form> element

  • any additional props will be passed down to the underlying <form> element

  • NOTE: onSubmit will only be called if the form passes validation!

Form element components

Input/Select/TextArea take all the same props.

import { Input, Select, TextArea } from '@tswaters/react-form-validation'
const example = () => (
  <>
    <Input // Select | TextArea
      validation={oneOfType([arrayOf(func), func])}
      other={oneOfType([arrayOf(string), string])}
      recheck={bool}
      blur={bool}
      change={bool}
      onError={func}
      onInvalid={func}
      onValid={func}
      onValidated={func}
    />
  </>
)
  • validation (field, others) => Promise<void|string|Error>

    An function, or array of functions. Will be called for validation with two parameters (field - reference to the input/select/textarea; others - an array of all form inputs). You can return:

    • an error
    • a string (this will be interpreted as an error)
    • null/undefined (returning nothing signifies validation passes)
    • throwing an error will be interpreted as failing validation
  • other string|string[] - provide the name or id of another element on the form. When validating this element, the other(s) will also have their validation routines called, assuming they have not yet been touched.

  • blur bool - validate this field on input blur

  • change bool - validate this field on input change

  • recheck bool - if recheck is passed as TRUE, once a form field is validated it will be revalidated on any change.

  • onError (Error|null) => void - will be called if there is a validation error. This will always be an error object (so check message / code), or null if there is no error.

  • onInvalid (bool) => void will be called after validation with a bool indicating the form field is invalid

  • onValid (bool) => void will be called after validation with a bool indicating the form field is valid

  • onValidated (bool) => void will be called after an input is validated.

Any additional props will be passed down to the underlying input/select/textarea element

Validator

import { Validator } from '@tswaters/react-form-validation'
const example = () => (
  <Validator recheck blur>
    {({ error, valid, invalid }) => (
      <>
        <label htmlFor="my-value">My Value</label>
        <input id="my-value" name="my-value" type="text" required />
        {valid && <div>valid</div>}
        {invalid && <div>invalid</div>}
        {error && <div>{error.message}</div>}
      </>
    )}
  </Validator>
)

The validator will find & replace all input/select/textarea elements with Input/Select/TextArea.

The render prop, ({ error, valid, invalid, validated }) will be updated with any feedback from the constraint validation API.

Any props provided to validator will be passed through to the underlying Input/Select/TextArea elements.

examples

implementing bootstrap's FormGroup

const FormGroup = ({ id, label, ...rest }) => {
  return (
    <Validator recheck blur>
      {({ error, validated }) => (
        <div className={`form-group ${validated ? 'was-validated' : ''}`}>
          <label className="control-label" htmlFor={id}>
            {label}
          </label>
          <input id={id} className="form-control" {...rest} />
          {error && <div className="invalid-feedback">{error.message}</div>}
        </div>
      )}
    </Validator>
  )
}

const LoginForm = () => {
  return (
    <Form onSubmit={(e) => e.preventDefault()}>
      <FormGroup id="user-name" name="user-name" label="User Name" required />
      <FormGroup
        id="password"
        name="password"
        label="Password"
        type="password"
        required
      />
      <button type="submit">Submit</button>
    </Form>
  )
}

custom validation functions

You can provide validations to the <Input/Select/TextArea> element and they will be called as part of validating the element.

Validation routines must be synchronous. Validation will be considered failed with the following returns:

  • a string - the error returned will be new Error(returnValue)

  • an error - the error returned will be returnValue

Otherwise, the validation is considered to have succeeded.

import { Form, Validator } from '@tswaters/react-form-validation'

const MyForm = () => {
  const [error, setError] = useState(null)
  const [response, setResponse] = useState(null)

  const validation = useCallback((inputRef) => {
    if (restrictedWords.includes(inputRef.value))
      return new Error('cant use restricted words')
  }, [])

  const handleSubmit = useCallback((e) => {
    e.preventDefault()
    console.log('completely valid, no restricted words here!')
  }, [])

  return (
    <Form onSubmit={handleSubmit} noValidate>
      <Validator change validation={validation}>
        {({ error }) => {
          return (
            <>
              <input name="user-name" required />
              {error && <div>{error.message}</div>}
            </>
          )
        }}
      </Validator>
      <button type="submit">Submit</button>
    </Form>
  )
}

a note on errors

Any errors for non-custom validation routines will be returned by the browser, so based upon the user's OS/browser language settings, you'll get different translated error messages, for better or worse.

message will be populated with the browser-defined error, and a code is also set that identifies the type of error that occured. As an example, an error raised from a required input not being provided might look something like this:

{
  "message": "Please provide a value",
  "code": "valueMissing"
}

You can override the translations by inspecting the code and providing the correct translation:

const ErrorDisplay = error => {
  const [t] = useTranslation() // or however else you get a translation function
  return error ? t(`validation-error-${error.code}` : null
}

For custom error messages, error.message will be whatever you returned or threw back and the code will be customError

Thoughts on Performance

  • make sure the tree passed via <Validator /> is pretty simple. Validator recursively traverses the tree and replaces html inputs with exports from this library.

  • validation functions should be memoized lest any change invoke a re-render (wrap functions with useCallback, or an array of functions with memo)

limitations / bugs

  • only the first error for a given input element will be returned

  • there's gunna be some weirdness with code returning incorrectly if multiple constraint errors are raised.