{"id":17159257,"url":"https://github.com/akuzko/react-form-base","last_synced_at":"2025-10-27T08:11:46.555Z","repository":{"id":65372983,"uuid":"78479611","full_name":"akuzko/react-form-base","owner":"akuzko","description":"Base React component for generic forms","archived":false,"fork":false,"pushed_at":"2019-10-03T13:31:11.000Z","size":207,"stargazers_count":18,"open_issues_count":2,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-09T01:38:22.687Z","etag":null,"topics":["controlled","form","formvalidation","javascript","react","react-component"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/akuzko.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-09T23:41:26.000Z","updated_at":"2020-09-24T04:28:42.000Z","dependencies_parsed_at":"2023-01-19T23:35:34.003Z","dependency_job_id":null,"html_url":"https://github.com/akuzko/react-form-base","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akuzko%2Freact-form-base","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akuzko%2Freact-form-base/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akuzko%2Freact-form-base/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akuzko%2Freact-form-base/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/akuzko","download_url":"https://codeload.github.com/akuzko/react-form-base/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248721062,"owners_count":21151039,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["controlled","form","formvalidation","javascript","react","react-component"],"created_at":"2024-10-14T22:13:48.209Z","updated_at":"2025-10-27T08:11:41.514Z","avatar_url":"https://github.com/akuzko.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"React Form Base\n===============\n\nBase Form component for building convenient forms for [React](https://facebook.github.io/react/).\n\n[![build status](https://img.shields.io/travis/akuzko/react-form-base/master.svg?style=flat-square)](https://travis-ci.org/akuzko/react-form-base)\n[![npm version](https://img.shields.io/npm/v/react-form-base.svg?style=flat-square)](https://www.npmjs.com/package/react-form-base)\n\n## Features Overview\n\n- Controlled Form, i.e. it accepts input values as a JSON object.\n- Simple API that handles deeply nested values and collections.\n- Flexible and convenient validation that allows to validate inputs as user types.\n- Allows to easily turn any existing component into a Form Input component.\n\n## Installation\n\n```\nnpm install --save react-form-base\n```\n\n## Usage\n\n### Input Prerequisites\n\n`react-form-base` provides a `Form` base class which expects to work together\nwith **Input** components. An **Input** is any component that consumes three\nproperties: `value`, `error` and `onChange`. It also has to provide it's\n`value` as first argument to `onChange` function supplied in props.\n*For existing ready-for-use input bindings take a look on:*\n- [react-form-js](https://github.com/akuzko/react-form-js)\n- [react-form-material-ui](https://github.com/akuzko/react-form-material-ui)\n\n### Form Usage\n\nMost of form use-cases with examples are revealed in [**Demo Application**](https://akuzko.github.io/react-form-base/).\nDetails on how to run it locally are at the end of README.\n\n#### Dedicated Forms\n\nMost of forms developers deal with are quite complicated and encapsulate\nvast amount of validation and rendering logic. After some basic setup described\nin the [Wiki](https://github.com/akuzko/react-form-base/wiki) your form may\nlook like following (please note that `$render` is a helper method and it is\npossible to use classic `render` method with a slightly more verbose result):\n\n```js\nclass UserForm extends Form {\n  validations = {\n    'email': ['presence', 'email'],\n    'fullName': 'presence',\n    'address.city': 'presence',\n    'address.line': { presence: true, format: /^[\\w\\s\\d\\.,]+$/ }\n  };\n\n  $render($) {\n    return (\n      \u003cdiv\u003e\n        \u003cTextField {...$('email')} label=\"Email\" /\u003e\n        \u003cTextField {...$('fullName')} label=\"Full Name\" /\u003e\n\n        \u003cSelect {...$('address.countryId')} options={countryOptions} label=\"Country\" /\u003e\n        \u003cTextField {...$('address.city')} label=\"City\" /\u003e\n        \u003cTextField {...$('address.line')} label=\"Address\" /\u003e\n\n        \u003cbutton onClick={this.save.bind(this)}\u003eSubmit\u003c/button\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n```\n\n#### Inline Forms\n\nIf your form is small enough, you might want to render it inline instead of\ndefining separate form component. In this case you may pass renderer function\nas only form's child. This function takes form's `$` function as argument for\nconvenience. Note that you still need to define static `validation` rules\nfor the Form to be able to use validations.\n\n```js\n\u003cForm {...bindState(this)} validations={{ email: ['presence', 'email'], fullName: 'presence' }}\u003e\n  {$ =\u003e (\n    \u003cdiv\u003e\n      \u003cTextField {...$('email')} label=\"Email\" /\u003e\n      \u003cTextField {...$('fullName')} label=\"FullName\" /\u003e\n      \u003cbutton onClick={this.registerUser}\u003eRegister\u003c/button\u003e\n    \u003c/div\u003e\n  )}\n\u003c/Form\u003e\n```\n\n#### API and helper methods\n\n- `$(name)`, `input(name)` - returns a set of properties for input with a given\n  name. `name` is a dot-separated string, i.e. `'foo.bar'` (for `bar` property\n  nested in object under `foo`), or `'foos.1'` (value at index 1 of `foos` array),\n  or `'foos.2.bar'` (`bar` property of object at index 2 of `foos` array)\n- `get(name)` - returns a value for a given name. For example, if you have an\n  attributes like `{foos: [{bar: 'baz'}, {bar: 'bak'}]}`, you might have:\n  - `this.get('foos')       // =\u003e [{bar: 'baz'}, {bar: 'bak'}]`\n  - `this.get('foos.1')     // =\u003e {bar: 'bak'}`\n  - `this.get('foos.1.bar') // =\u003e 'bak'`\n  - `this.get() // returns whole form's attributes object`\n- `set(name, value, meta)` - sets a `value` for an input with a specified `name`.\n  Optional `meta` argument will be passed to `props.onChange` function alongside\n  with new `attrs` as second argument.\n- `set(object, meta)` - sets multiple values at once. Each key in the object\n  corresponds to input name, and values are input values. Optional `meta` argument\n  will be passed to `props.onChange` function alongside with new `attrs` as second\n  argument.\n- `merge(name, value)` - merges given `value` object with value of input with\n  a given `name`. Should be used when working with nested forms.\n- `push(name, value)` - pushes a `value` to an input (which is treated as array)\n  with a given `name`.\n- `remove(name, index)` - removes an item of an input (which is treated as array)\n  with a given `name` at index `index`.\n- `each(name, iteratee)` - iterates with `iteratee` over items in an\n  input with a given `name`, passing item and index to `iteratee`.\n- `map(name, iteratee)` - maps with `iteratee` over items in an\n  input with a given `name`, passing item and index to `iteratee`.\n- `mapExtra(path, iteratee)` - maps with `iteratee` over items in an\n  input with a given `name`, passing item and index to `iteratee`. Makes\n  additional iteration that passes `null` and length of items to `iteratee`\n- `getValidationErrors()` - returns validation errors.\n- `performValidation()` - runs validation routines and sets errors.\n- `ifValid(successCallback, failureCallback)` - runs validation routines, sets errors,\n  and executes `successCallback` if there were no errors. Otherwise, executes\n  `failureCallback`, if is was passed, **or** `props.onValidationFailed`\n- `getErrors()` - returns an errors object.\n- `getError(name)` - returns an error for an input with a given `name`.\n- `setErrors(errors)` - sets `errors` (object) as form's errors.\n- `save()` - if `this.props.validateOnSave` is `true` (which is default value),\n  performs validation and calls `this.props.onRequestSave(this.get(), this);` if\n  there were no errors. if `validateOnSave` property is `false`, calls\n  `this.props.onRequestSave(this.get(), this);` immediately.\n- `reset(attrs = {})` - calls `this.props.onChange(attrs)` and clears errors.\n\n#### Form's props\n\n| Prop Name             | Spec                                  | Description |\n|-----------------------|---------------------------------------|-------------|\n| `attrs`               | `PropTypes.object.isRequired`         | Form's attributes - the values of form's inputs |\n| `onChange`            | `PropTypes.func`                      | A callback that is called whenever form's input changes it's value. Form's `attrs` and optional `meta` object (see `set` method description above) are passed to it. Typically has a form of `(formAttrs) =\u003e this.setState({ formAttrs })` |\n| `clearErrorsOnChange` | `PropTypes.bool`, defaults to `true`  | If input has an error on it and this property is enabled, error will be cleared when input changes its value |\n| `validateOnChange`    | `PropTypes.bool`, defaults to `true`  | If form has input validations defined, and validation routines were called with unsuccessful result, enabling this property will re-validate input when its value changes |\n| `validateOnSave`      | `PropTypes.bool`, defaults to `true`  | If `true`, on `save` method call form will run validations first and execute `onRequestSave` callback only if there were no errors |\n| `onRequestSave`       | `PropTypes.func`                      | This callback is called in `Form#save` method, passing form's `attrs` and form object itself to it |\n| `onValidationFailed`  | `PropTypes.func`                      | This callback is called if form's validation routines resulted in errors. Those `errors` and form object itself are passed to it |\n\n### Form Container\n\n`react-form-base`'s `Form` is a controlled form component, which means that\nattributes it works with are supplied from outer component in `props`. This\nalso means that proper (yet trivial) `onChange` function should be also supplied.\n\n```js\nimport React, { Component } from 'react';\nimport MyForm from 'my-form';\n\nclass Page extends Component {\n  state = { item: {} };\n\n  saveItem = (item, form) =\u003e {\n    // stubbed AJAX request code (with axios-like error)\n    post('/items', { item })\n      .then(() =\u003e this.setState({ item: {} }))\n      .catch((err) =\u003e form.setErrors(err.response.data));\n  };\n\n  render() {\n    return (\n      \u003cMyForm\n        attrs={this.state.item}\n        onChange={(item) =\u003e this.setState({ item })}\n        onRequestSave={this.saveItem}\n      /\u003e\n    );\n  }\n}\n```\n\n#### `bindState` helper function\n\n`react-form-base` also ships `bindState(component, key = 'form')` helper function\nthat will generate `{ attrs, onChange }` props object for a given component.\nFor instance, form from example above using this helper will look like so:\n\n```js\nimport React, { Component } from 'react';\nimport { bindState } from 'react-form-base';\nimport MyForm from 'my-form';\n\nclass Page extends Component {\n  saveItem = (item, form) =\u003e {\n    // ...\n  };\n\n  render() {\n    return \u003cMyForm {...bindState(this, 'item')} onRequestSave={this.saveItem} /\u003e;\n  }\n}\n```\n\n## Credits\n\nHugs and thanks to [ogrechishkina](https://github.com/ogrechishkina) for her\nsupport and building all of the CSS for demo application.\n\n## Running Demo locally\n\n```\n$ git clone git@github.com:akuzko/react-form-base.git\n$ cd react-form-base\n$ npm i\n$ cd demo\n$ npm i\n$ gulp\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakuzko%2Freact-form-base","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fakuzko%2Freact-form-base","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakuzko%2Freact-form-base/lists"}