# react-validable

> Simple configless validation for React

Latest version **0.5.4** (published 2018-05-23) · MIT license · 5 weekly downloads

## Install

```sh
npm install react-validable
pnpm add react-validable
yarn add react-validable
bun add react-validable
```

## Health

**Score 5/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support; pre 1.0.

Negative: abandoned; low maintenance score; declining downloads.

## Facts

| | |
|---|---|
| Version | 0.5.4 |
| Published | 2018-05-23 |
| First published | 2017-10-05 |
| Weekly downloads | 5 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 0 |
| Unpacked size | 3.4 MB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | Igor Koptelov |
| Maintainers | sick-sad-world |
| Keywords | react, forms, validaton |

## Links

- npm: https://www.npmjs.com/package/react-validable
- Repository: https://github.com/sick-sad-world/react-validable
- Issues: https://github.com/sick-sad-world/react-validable/issues
- npm.io page: https://npm.io/package/react-validable

## Alternatives

- [mobx-react](https://npm.io/package/mobx-react.md) — 2.8M weekly downloads
- [rc-tree](https://npm.io/package/rc-tree.md) — 2.6M weekly downloads
- [@react-oauth/google](https://npm.io/package/@react-oauth/google.md) — 1.3M weekly downloads
- [@wagmi/connectors](https://npm.io/package/@wagmi/connectors.md) — 877.0K weekly downloads
- [vee-validate](https://npm.io/package/vee-validate.md) — 836.4K weekly downloads

## Recent versions

- 0.5.4 (latest) — 2018-05-23
- 0.5.1 — 2017-10-25
- 0.5.3 — 2017-10-09
- 0.5.2 — 2017-10-06
- 0.5.0 — 2017-10-05

## README

# react-validable
==============

[![npm Version](https://img.shields.io/npm/v/react-validable.svg)](https://www.npmjs.com/package/react-validable) [![License](https://img.shields.io/npm/l/react-validable.svg)](https://www.npmjs.com/package/react-validable)
[![bitHound Overall Score](https://www.bithound.io/github/sick-sad-world/react-validable/badges/score.svg)](https://www.bithound.io/github/sick-sad-world/react-validable)
[![Codecov](https://img.shields.io/codecov/c/github/sick-sad-world/react-validable.svg)](https://codecov.io/github/sick-sad-world/react-validable)

Simple configless validation for React. Only simple High-Ordered Components and rules.

**No field configuration needed!**

## Installation

```
$ npm install react-validable  --save
```

## Testing

Go to project folder and run
```
$ npm install
$ npm test
```

## Usage Guide

See exampes here https://sick-sad-world.github.io/react-validable/

### Step One - Make field suitable for validation

You may take whatever form input component you have. After being wrapped by `Validable.Element` it recieve props listed in table below. **If you pass props with same names they will be overritten**

#### Props injected to Child Component
 - `valid` - represents current validation state `true` if valid. `Array[String]` of messages otherwise.
 -  `pristine` - `Boolean` - Determine whatever field was touched or not. Most of time it equals `false` (Scope - Elemnt) Global form pristine state you manage by our own
 - `validate` - `function(val, opts)` Function given to check whatever new value is valid.
 
#### Validate function usage
Syntax `validate(value, options)`.

Params:
 - `value` - value to check validation
 - `options` - `Array[Object]` Options to override. Should be an array of 1 to [n] items.

> **Note** options will be passed in the order as rules defined in `Validable.Element` HOC. So if you have `Validable.Element(['required', 'numeric'])` options `[{message: 'Required'}, {message: 'Numeric'}]` will be passed accordinately. If you need to update options only for `numeric` you should use something like this `[null, {message: 'Numeric'}]`

> **Note** Dosen't matter how and when you call `validate` method it changes global `Validable.Form` state through context. You can pass result in `onChange` handler or `onBlur` and build whatever interaction you want. Read more for details.


```JavaScript
export default function TextInput({ label, type, name, value, validate, valid, pristine, onChange, ...props }) {

  // Check file validation
  const invalid = Array.isArray(valid);

  // Define change handler 
  const changeHandler = (e) => {
    onChange(
      { [name]: e.target.value },
      validate(
        // Value to check
        e.target.value, 
        // You can change options here like message or validation specific ones 
        [{message: 'Required message'}, {message: 'Numeric message'}] 
      ) 
    );
  };

  // Set class if field is invalid and was changed
  const className = `row ${(invalid && !pristine) ? 'invalid' : ''}`;

  // Show message if field is invalid and was changed
  const message = (invalid && !pristine) ? <span>{valid.join(', ')}</span> : null;

  return (
    <div className={className}>

      <label htmlFor={`id-${name}`}>{label}</label>

      <input
        id={`id-${name}`}
        type={type}
        name={name}
        value={value || ''} 
        onChange={changeHandler}
        {...props}
      />

      {message}
    </div>
  );
}
```

### Step Two - Create fields with validation

 - Import `Validable.Element` hoc
 - Wrap your input and define rules
 - Use it in form

#### Validation rule syntax

```JavaScript
import Validable from 'react-validable';
// or
import { Element } from 'react-validable';

// Simple one-rule validation w/o options
// If you want declare one rule with default options
const NameInput = Validable.Element('required')(YourAwesomeInput);

// Simple one-rule validation with options
// If you want declare one rule with default options
const TextInput = Validable.Element({
  type: 'maxLength',                              // pick rule 
  treshold: 100,                                  // provide option required by rule
  message: 'Text should be less than 100 symbols' // Customize message
})(YourAwesomeInput);

// You may pass any number of rules in array in any form
const ZipCodeInput = Validable.Element(['required', {
  type: 'maxLength',                              // pick rule 
  treshold: 6,                                    // provide option required by rule
  message: 'Text should be less than 100 symbols' // Customize message
}])(YourAwesomeInput);

// You can cache settings as it presumed in React-Redux connect method and use preset for multiple inputs

const RequiredDecimal = Validable.Element(['required', 'decimal']);

const Input1 = RequiredDecimal(YourAwesomeInput);
const Input2 = RequiredDecimal(YourAwesomeInput);
const Input3 = RequiredDecimal(YourAwesomeInput);

// Somewhere inside your form component
// ======================================================================
render() {
  return (
    <form>
      <NameInput name='name' value={value} onChange={this.onChange}>
      <TextInput name='text' value={value} onChange={this.onChange}>
      <ZipCodeInput name='zip' value={value} onChange={this.onChange}>
    </form>
  )
}
```

#### Connect inputs together
Common case: Match password fields

Create two fields with `equal` matchers. And provide values to opposing field.

```JavaScript
// Field one
const Pass1 = Validable.Element('equal')(Field);

// Retype password
const Pass2 = Validable.Element('equal')(Field);

// Somewhere in form
render() {
  <form>
    <Pass1 value={pass1} match={pass1}/>
    <Pass2 value={pass2} match={pass2}/>
  </form>
}

// In input fields
class Field extends React.Component {
  componentWillReceiveProps(nextProps) {
    // To handle change of other input you may use lifecycle hooks
    if (this.props.match !== newProps.match) {
      // Compare current value with new match
      this.props.validate(this.props.value, newProps.match);
    }
  }

  onChange() {
    // You can match value with opponent value on change or blur or whatever you want
    this.props.validate(this.props.value, [{math: this.props.match}]);
  }
  render() {
    <input type='password' onChange={this.onChange} value={this.props.value} />
  }
}

```


#### Options flow.
You have number of possibilities to define options

Here they is given in order. Bottom one may override upper one.
 - in validator (When you create your own custom Validator)
 - while using `Validable.Element` HOC where you define rules
 - right in `validate` function call inside input

### Part Three - Put Your validation All-Together
To get results of validation in cetralized manner `Validable.Form` HOC provided

How to use it:
 - Create your form component
 - Make sure Form accepts `valid` property as `Boolean`
 - You can get whole validation state by passing `exposeRaw={true}` to your Form component
 - You can control validation state from outside using `onValidation={Function}` property

```JavaScript
  import Validable from 'react-validable';
  // or
  import { Form } from 'react-validable';

  class AwesomeForm extends React.Component {
    onSubmit(e) {
      e.preventDefault();
      if (this.props.valid) {
        // Do something
      }
    }
    render() {
      // This will be full validation state copy. if [exposeRaw] is passed
      const { validationState } = this.props;

      return (
        <form onSubmit={this.onSubmit}>{Some form stuff}</form>
      )
    }
  }

  export default Validable.Form(AwesomeForm);

  // Use it somewhere
  <AwesomeForm
    exposeRaw={true} // Get whole validation state
    onValidation={someOutsideCallback(valid = Bool, state = Object)} // Get validation from outside
  />
```

> **Note!** You may use `Validable.Element` **WITHOUT** `Validable.Form` but then you need to manage whole validation state by your own with `validate` method return values, or through defining your own `updatePosition` context handler <br/> with this signature `function({ key: inputId, valid: bool or [message]})`


### Part Four - Validation rules list
`message` - validation error message - common for **ALL** rules

|Name|Opions|Description|
|:---|:---|:---|
|`required`|none|Check if `value` is not `null` or `undefined`|
|`match`|`pattern` - `RegExp` to match |Match value to given `RegExp`|
|`numeric`|none|Check if `value` is number|
|`float`|none|Check if `value` is float|
|`url`|none|Check if `value` is valid URL adderss|
|`email`|none|Check if `value` is valid email address|
|`maxLength`|`treshold` - `Number` string lenght limit|Check if `value` is string length less than limit|
|`oneOf`|`possible` - `Array` choises to match|Check if `value` matches one of given options|
|`file`|`size` - `Number` max sie in Kbs<br/>`type` - `String` or `Array[String]` - mime-types acceptable by input |Specialized validator for `file` type inputs. Can check file size and mime-type.|

> **Note** in rule not found `Validable.Element` will throw an Error. You may add new rules via method described below

### Part Five - Add new Validation rule via `addRule`

Extends global rules object with given rules

```JavaScript
  import Validable from 'react-validable';
  // or
  import { addRules } from 'react-validable';

  Validable.addRules({
    customRule: (value, {message, opt1, opt2, ...opts}) => {
      if (valid) {
        // Validator should return [true] if value is valid
        return true;
      } else {
        // Or text message if something wrong
        return 'Some message';
      }
    }
  })
```

Now you can use custom rule.

```JavaScript
  // And use it 
  Validabe.Element(['required', 'customRule'])(SomeInput);
  // or with options
  Validabe.Element(['required', {
    rule: 'customRule',
    opt1: 'bar',
    opt2: 'foo'
  }])(SomeInput);
```
## Licence

This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details

---
_Source: https://npm.io/package/react-validable · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
