{"id":16178520,"url":"https://github.com/seeden/react-form-controlled","last_synced_at":"2025-08-22T18:14:00.538Z","repository":{"id":52163432,"uuid":"37694065","full_name":"seeden/react-form-controlled","owner":"seeden","description":"Intuitive react forms for building powerful applications.","archived":false,"fork":false,"pushed_at":"2022-12-06T16:52:20.000Z","size":819,"stargazers_count":51,"open_issues_count":15,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-08-09T14:28:13.756Z","etag":null,"topics":["fieldset","form","javascript","react","react-components","redux"],"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/seeden.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-06-19T01:07:28.000Z","updated_at":"2024-01-12T14:46:20.000Z","dependencies_parsed_at":"2023-01-24T02:01:10.904Z","dependency_job_id":null,"html_url":"https://github.com/seeden/react-form-controlled","commit_stats":null,"previous_names":[],"tags_count":139,"template":false,"template_full_name":null,"purl":"pkg:github/seeden/react-form-controlled","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seeden%2Freact-form-controlled","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seeden%2Freact-form-controlled/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seeden%2Freact-form-controlled/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seeden%2Freact-form-controlled/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/seeden","download_url":"https://codeload.github.com/seeden/react-form-controlled/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seeden%2Freact-form-controlled/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271680336,"owners_count":24802074,"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","status":"online","status_checked_at":"2025-08-22T02:00:08.480Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["fieldset","form","javascript","react","react-components","redux"],"created_at":"2024-10-10T05:13:55.839Z","updated_at":"2025-08-22T18:14:00.512Z","avatar_url":"https://github.com/seeden.png","language":"JavaScript","readme":"# React controlled form\n\nIntuitive react forms for building powerful applications.\n\nAll components are [controlled](https://facebook.github.io/react/docs/forms.html#why-controlled-components)\nThat means form is always showing the current state and data are immutable.\nEach form has own internal state that means you can skip onChange event.\nIf you will change the value prop of the form component it will change the state of the form immediately.\n\n[![NPM version][npm-image]][npm-url]\n[![build status][travis-image]][travis-url]\n[![Test coverage][coveralls-image]][coveralls-url]\n\n[npm-image]: https://img.shields.io/npm/v/react-form-controlled.svg?style=flat-square\n[npm-url]: https://www.npmjs.com/react-form-controlled\n[travis-image]: https://img.shields.io/travis/seeden/react-form-controlled/master.svg?style=flat-square\n[travis-url]: https://travis-ci.org/seeden/react-form-controlled\n[coveralls-image]: https://img.shields.io/coveralls/seeden/react-form-controlled/master.svg?style=flat-square\n[coveralls-url]: https://coveralls.io/r/seeden/react-form-controlled?branch=master\n[github-url]: https://github.com/seeden/react-form-controlled\n\n# Features\n\n- Immutable data\n- Controlled behavior (support for \"uncontrolled\" behaviour)\n- Build on latest standards ES6 and promises\n- Support for isomorphic application\n- You are able to use forms without special components\n- Support for arrays/lists and indexes\n- Standard html elements like an input, select, textarea and fieldset (arrays)\n- Custom components and support for 3rd party libraries\n- Validation\n- Tests and coverage\n\n\n# Support us\n\nStar this project on [GitHub][github-url].\n\n# Examples\n\n## Simple usage\n\n```js\nimport React, { Component } from 'react';\nimport Form from 'react-form-controlled';\n\nexport default class Example extends Component {\n  constructor(props, context) {\n    super(props, context);\n\n    this.formData = {\n      firstName: null,\n      lastName: null\n    };\n  }\n\n  onSubmit = (data) =\u003e {\n    alert(`Hi ${data.firstName} ${data.lastName}`);\n  }\n\n  render() {\n    return (\n      \u003cForm\n        value={this.formData}\n        onSubmit={this.onSubmit}\n      \u003e\n        \u003clabel\u003e\n          \u003cinput name=\"firstName\" /\u003e\n        \u003c/label\u003e\n\n        \u003clabel\u003e\n          \u003cinput name=\"lastName\" /\u003e\n        \u003c/label\u003e\n\n        \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n      \u003c/Form\u003e\n    );\n  }\n}\n```\n\n## Where is the input value?\n\nValue is automatically added as prop to the inputs. When you will change it it will reload whole form (controlled form, but this is the work for React).\n\n## Arrays and controlled state\n\n```js\nimport React, { Component } from 'react';\nimport Form from 'react-form-controlled';\n\nexport default class Example extends Component {\n  constructor(props, context) {\n    super(props, context);\n\n    this.state = {\n      users: [{\n        firstName: 'Zlatko'\n      }, {\n        firstName: 'Livia'\n      }]\n    };\n  }\n\n  onChange = (data) =\u003e {\n    this.setState(data);\n  }\n\n  onSubmit = (data) =\u003e {\n    alert(`Hi ${data.users[0].firstName}`);\n  }\n\n  render() {\n    return (\n      \u003cForm\n        value={this.state}\n        onChange={this.onChange}\n        onSubmit={this.onSubmit}\n      \u003e\n        \u003cfieldset name=\"users\"\u003e\n          \u003clabel\u003e\n            \u003cinput name=\"firstName\" /\u003e\n          \u003c/label\u003e\n        \u003c/fieldset\u003e\n\n        \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n      \u003c/Form\u003e\n    );\n  }\n}\n```\n\n## You can do what do you want with value.\n\n```js\nimport React, { Component } from 'react';\nimport Form from 'react-form-controlled';\n\nexport default class Example extends Component {\n  constructor(props, context) {\n    super(props, context);\n\n    this.state = {\n      users: [{\n        firstName: 'Zlatko'\n      }, {\n        firstName: 'Livia'\n      }]\n    };\n  }\n\n  onChange = (data) =\u003e {\n    this.setState(data);\n  }\n\n  onSubmit = (data) =\u003e {\n    alert(`Hi ${data.users[0].firstName}`);\n  }\n\n  render() {\n    return (\n      \u003cForm\n        value={this.state}\n        onChange={this.onChange}\n        onSubmit={this.onSubmit}\n      \u003e\n        \u003cRow\u003e\n          \u003cfieldset \n            name=\"users\"\n            render={({ value }) =\u003e value.map((user, index) =\u003e (\n              \u003cColumn\u003e\n                \u003cfieldset name={index}\u003e\n                  \u003clabel\u003e\n                    \u003cinput name=\"firstName\" /\u003e\n                  \u003c/label\u003e\n                \u003c/fieldset\u003e\n              \u003c/Column\u003e\n            ))}\n          /\u003e\n          \u003c/fieldset\u003e\n        \u003c/Row\u003e\n\n        \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n      \u003c/Form\u003e\n    );\n  }\n}\n```\n\n\n## Simple arrays\n\nIf you are using fieldset with simple array do not enter the name attribute.\n\n```js\nimport React, { Component } from 'react';\nimport Form from 'react-form-controlled';\n\nexport default class Example extends Component {\n  constructor(props, context) {\n    super(props, context);\n\n    this.state = {\n      items: [123, 222]\n    };\n  }\n\n  onSubmit = (data) =\u003e {\n    alert(`Hi ${data.users[0].firstName}`);\n  }\n\n  render() {\n    return (\n      \u003cForm\n        value={this.state}\n        onSubmit={this.onSubmit}\n      \u003e\n        \u003cfieldset name=\"items\"\u003e\n          \u003cinput type=\"text\" /\u003e\n        \u003c/fieldset\u003e\n\n        \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n      \u003c/Form\u003e\n    );\n  }\n}\n```\n\n## Complex objects\n\nIf you want to use complex names you can use dot or array notation.\n\n```js\nimport React, { Component } from 'react';\nimport Form from 'react-form-controlled';\n\nexport default class Example extends Component {\n  constructor(props, context) {\n    super(props, context);\n\n    this.state = {\n      users: [{\n        firstName: 'Zlatko',\n        stats: {\n          followers: 10,\n        },\n      }, {\n        firstName: 'Livia',\n        stats: {\n          followers: 22,\n        },\n      }]\n    };\n  }\n\n  onSubmit = (data) =\u003e {\n    alert(`Hi ${data.users[0].firstName}`);\n  }\n\n  render() {\n    return (\n      \u003cForm\n        value={this.state}\n        onSubmit={this.onSubmit}\n      \u003e\n        \u003cfieldset name=\"users\"\u003e\n          \u003clabel\u003e\n            \u003cinput name=\"firstName\" /\u003e\n          \u003c/label\u003e\n          \u003clabel\u003e\n            \u003cinput name=\"stats.followers\" /\u003e\n          \u003c/label\u003e\n        \u003c/fieldset\u003e\n\n        \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n      \u003c/Form\u003e\n    );\n  }\n}\n```\n\nor you can use one more fieldset\n\n```js\nimport React, { Component } from 'react';\nimport Form from 'react-form-controlled';\n\nexport default class Example extends Component {\n  constructor(props, context) {\n    super(props, context);\n\n    this.state = {\n      users: [{\n        firstName: 'Zlatko',\n        stats: {\n          followers: 10,\n        },\n      }, {\n        firstName: 'Livia',\n        stats: {\n          followers: 22,\n        },\n      }]\n    };\n  }\n\n  onSubmit = (data) =\u003e {\n    alert(`Hi ${data.users[0].firstName}`);\n  }\n\n  render() {\n    return (\n      \u003cForm\n        value={this.state}\n        onSubmit={this.onSubmit}\n      \u003e\n        \u003cfieldset name=\"users\"\u003e\n          \u003clabel\u003e\n            \u003cinput type=\"text\" name=\"firstName\" placeholder=\"First name\" /\u003e\n          \u003c/label\u003e\n          \u003cfieldset name=\"stats\"\u003e\n            \u003clabel\u003e\n              \u003cinput type=\"text\" name=\"followers\" placeholder=\"Followers\" /\u003e\n            \u003c/label\u003e\n          \u003c/fieldset\u003e\n        \u003c/fieldset\u003e\n\n        \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n      \u003c/Form\u003e\n    );\n  }\n}\n```\n\n## Indexes\n\nIf you are using arrays with fieldset you want to use indexes.\n\n### Props\n\n#### render: function\n\nInstead of having a component rendered for you, you can pass in a function. Your render function will be called with the same props that are passed to the component.\n\n```js\nimport React, { Component } from 'react';\nimport Form, { Index } from 'react-form-controlled';\n\nexport default class Component extends Component {\n  constructor(props, context) {\n    super(props, context);\n\n    this.state = {\n      users: [{\n        firstName: 'Zlatko',\n      }, {\n        firstName: 'Livia',\n      }]\n    };\n  }\n\n  onSubmit = (data) =\u003e {\n    alert(`Hi ${data.users[0].firstName}`);\n  }\n\n  render() {\n    return (\n      \u003cForm\n        value={this.state}\n        onSubmit={this.onSubmit}\n      \u003e\n        \u003cfieldset name=\"users\"\u003e\n          \u003clabel\u003e\n            \u003cIndex \n              render={({ index }) =\u003e (\n                \u003cspan\u003e{index}.\u003c/span\u003e\n              )} \n            /\u003e\n            \u003cinput name=\"firstName\" /\u003e\n          \u003c/label\u003e\n        \u003c/fieldset\u003e\n\n        \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n      \u003c/Form\u003e\n    );\n  }\n}\n```\n\n## Parent values\n\nYou can use value from parent with dot notation. Example \".selected\"\n\n```js\nimport React, { Component } from 'react';\nimport Form, { Index } from 'react-form-controlled';\n\nexport default class Component extends Component {\n  constructor(props, context) {\n    super(props, context);\n\n    this.state = {\n      options: ['dog', 'mouse', 'cat'],\n      selected: 1,\n    };\n  }\n\n  onSubmit = (data) =\u003e {\n    alert(`Selected option is ${data.options[data.selected]}`);\n  }\n\n  render() {\n    return (\n      \u003cForm\n        value={this.state}\n        onSubmit={this.onSubmit}\n      \u003e\n        \u003cfieldset name=\"options\"\u003e\n          \u003cIndex\n            render={({ index }) =\u003e (\n              \u003cinput type=\"radio\" name=\"..selected\" value={index} /\u003e\n            )}\n          /\u003e\n          \u003cinput name=\".\" /\u003e\n        \u003c/fieldset\u003e\n\n        \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n      \u003c/Form\u003e\n    );\n  }\n}\n```\n\n## Integrate with 3rd party libraries\n\nIntegration is very easy you can use Integrate component. Here is example with [react-select](https://github.com/JedWatson/react-select) library.\n### Props\n#### value: string\nName of the integrated value property.\n#### onChange: function\nOnChange callback of the integrated component.\n#### name: string\nName of the state property. You can use standard dot notation as always :)\n\n```js\nimport React, { Component } from 'react';\nimport Form, { Integrate } from 'react-form-controlled';\nimport Select from 'react-select';\n\nexport default class Component extends Component {\n  onSubmit = (data) =\u003e {\n    alert(`Selected option is ${data.selected}`);\n  }\n\n  render() {\n    const options = [\n      { value: 'one', label: 'One' },\n      { value: 'two', label: 'Two' }\n    ];\n\n    return (\n      \u003cForm\n        onSubmit={this.onSubmit}\n      \u003e\n        \u003cIntegrate \n          name=\"selected\" \n          render={({ value, onChange }) =\u003e (\n            \u003cSelect options={options} value={value} onChange={onChange} /\u003e\n          )}\n        /\u003e\n\n        \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n      \u003c/Form\u003e\n    );\n  }\n}\n```\n\n## Remove item from array\n\n```js\nimport React, { Component } from 'react';\nimport Form, { Remove } from 'react-form-controlled';\n\nexport default class Component extends Component {\n  constructor(props, context) {\n    super(props, context);\n\n    this.state = {\n      users: [{\n        firstName: 'Zlatko',\n      }, {\n        firstName: 'Livia',\n      }]\n    };\n  }\n\n  onSubmit = (data) =\u003e {\n    alert(`Hi ${data.users[0].firstName}`);\n  }\n\n  render() {\n    return (\n      \u003cForm\n        value={this.state}\n        onSubmit={this.onSubmit}\n      \u003e\n        \u003cfieldset name=\"users\"\u003e\n          \u003clabel\u003e\n            \u003cinput name=\"firstName\" /\u003e\n            \u003cRemove \n              render={({ onClick }) =\u003e (\n                \u003cbutton type=\"button\" onClick={onClick}\u003eRemove\u003c/button\u003e\n              )} \n            /\u003e\n          \u003c/label\u003e\n        \u003c/fieldset\u003e\n\n        \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n      \u003c/Form\u003e\n    );\n  }\n}\n```\nRemove, Up and Down components has same properties like index. You can use render and component property as well.\n\n## Move item up/down in array\n\n```js\nimport React, { Component } from 'react';\nimport Form, { Up, Down } from 'react-form-controlled';\n\nexport default class Component extends Component {\n  constructor(props, context) {\n    super(props, context);\n\n    this.state = {\n      users: [{\n        firstName: 'Zlatko',\n      }, {\n        firstName: 'Livia',\n      }]\n    };\n  }\n\n  onSubmit = (data) =\u003e {\n    alert(`Hi ${data.users[0].firstName}`);\n  }\n\n  render() {\n    return (\n      \u003cForm\n        value={this.state}\n        onSubmit={this.onSubmit}\n      \u003e\n        \u003cfieldset name=\"users\"\u003e\n          \u003cinput name=\"firstName\" /\u003e\n          \u003cUp \n            render={({ onClick }) =\u003e (\n              \u003cbutton type=\"button\" onClick={onClick}\u003eUp\u003c/button\u003e\n            )} \n          /\u003e\n          \u003cDown \n            render={({ onClick }) =\u003e (\n              \u003cbutton type=\"button\" onClick={onClick}\u003eDown\u003c/button\u003e\n            )} \n          /\u003e\n        \u003c/fieldset\u003e\n\n        \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n      \u003c/Form\u003e\n    );\n  }\n}\n```\n\n## Working state\n\nYou can simply handle working state and show loading indicator. Form property onSubmit is based on promises. During you processing of this callback is form in the \"isWorking\" state.\nIf the form is in the isWorking state you are not able to submit form again.\n\n```js\nimport React, { Component } from 'react';\nimport Form, { Working } from 'react-form-controlled';\n\nexport default class Component extends Component {\n  constructor(props, context) {\n    super(props, context);\n\n    this.state = {\n      users: [{\n        firstName: 'Zlatko',\n      }, {\n        firstName: 'Livia',\n      }]\n    };\n  }\n\n  onSubmit = async (data) =\u003e {\n    return new Promise((resolve) =\u003e {\n      alert(`Hi ${data.users[0].firstName}`);\n\n      setTimeout(resolve, 3000);\n    });\n  }\n\n  render() {\n    return (\n      \u003cForm\n        value={this.state}\n        onSubmit={this.onSubmit}\n      \u003e\n        \u003cfieldset name=\"users\"\u003e\n          \u003cinput name=\"firstName\" /\u003e\n        \u003c/fieldset\u003e\n\n        \u003cWorking \n          render={({ isWorking }) =\u003e isWorking ? 'isWorking' : 'idle'} \n        /\u003e\n        \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n      \u003c/Form\u003e\n    );\n  }\n}\n```\n\n## So far so good (more complex form)\n\nTry to image simple quiz with questions and answers. Y\n\n## Combination with other components\n\nIf you want to disable autoreplace of the standard components like an input, select, textarea etc...\nYou can disable this behavior with the form parameter skipReplace.\nThis feature is great if you want to use this library with other 3rd libraries.\nYou will be able to use Input, Select, Textarea and Fieldset.\n\n```js\nimport Form, { Input, Select, Textarea, Fieldset } from from 'react-form-controlled';\n\nexport default class Component extends Component {\n  constructor(props, context) {\n    super(props, context);\n\n    this.state = {\n      users: [{\n        firstName: 'Zlatko',\n      }, {\n        firstName: 'Livia',\n      }]\n    };\n  }\n\n  onSubmit(data) {\n    alert(`Hi ${data.users[0].firstName}`);\n  }\n\n  render() {\n    return (\n      \u003cForm\n        value={this.state}\n        onSubmit={this.onSubmit}\n        skipReplace\n      \u003e\n        \u003cFieldset name=\"users\"\u003e\n          \u003clabel\u003e\n            \u003cIndex render={({ index }) =\u003e index} /\u003e\n            \u003cInput type=\"text\" name=\"firstName\" placeholder=\"First name\" /\u003e\n          \u003c/label\u003e\n        \u003c/Fieldset\u003e\n\n        \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n      \u003c/Form\u003e\n    );\n  }\n}\n```\n\n# Support for schemas and validation?\n\nThis part is moved to another library named react-form-controlled-validate\n\nYes, you can use JSON schema as property to the form. Why JSON schema? Because it is a standard.\n```js\n\nconst schema = {\n  type: \"object\",\n  properties: {\n    firstName: {\n      type: \"string\"\n    },\n    lastName: {\n      type: \"string\"\n    }\n  }\n};\n\n\u003cForm schema={schema} ref=\"form\"\u003e\n\nconst hasError = form.hasError('firstName'); //true\nconst isValid = from.isValid('firstName'); //false\nconst errors = form.getErrors(); //[{path: 'firstName', error: '...'}]\n```\n\n# Support us\n\nStar this project on [GitHub][github-url].\n\n## Try our other React components\n\n - Translate your great project [react-translate-maker](https://github.com/CherrySoftware/react-translate-maker)\n - Google Analytics [react-g-analytics](https://github.com/seeden/react-g-analytics)\n - Google AdSense via Google Publisher Tag [react-google-publisher-tag](https://github.com/seeden/react-google-publisher-tag)\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2017 [Zlatko Fedor](http://github.com/seeden)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseeden%2Freact-form-controlled","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fseeden%2Freact-form-controlled","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseeden%2Freact-form-controlled/lists"}