{"id":4494,"url":"https://github.com/bietkul/react-reactive-form","last_synced_at":"2025-04-12T22:20:07.076Z","repository":{"id":27521681,"uuid":"111069113","full_name":"bietkul/react-reactive-form","owner":"bietkul","description":"Angular like reactive forms in React.","archived":false,"fork":false,"pushed_at":"2023-10-18T02:42:45.000Z","size":1762,"stargazers_count":310,"open_issues_count":19,"forks_count":33,"subscribers_count":12,"default_branch":"mono-repo","last_synced_at":"2025-04-09T22:27:23.931Z","etag":null,"topics":["async-validation","asynchronous","form-builder","form-controls","form-fields","form-generator","form-validation","forms","observable","observer","react","react-forms","react-native","reactive-forms","subscription"],"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/bietkul.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null},"funding":{"github":null,"patreon":null,"open_collective":"react-reactive-form","ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2017-11-17T06:55:59.000Z","updated_at":"2025-04-09T13:46:25.000Z","dependencies_parsed_at":"2023-11-07T17:03:01.663Z","dependency_job_id":"a5893258-c8bf-4aca-a8b1-4509ad90d245","html_url":"https://github.com/bietkul/react-reactive-form","commit_stats":{"total_commits":280,"total_committers":10,"mean_commits":28.0,"dds":"0.16785714285714282","last_synced_commit":"77c1d62efc980904013af98705c9e081466a5780"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bietkul%2Freact-reactive-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bietkul%2Freact-reactive-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bietkul%2Freact-reactive-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bietkul%2Freact-reactive-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bietkul","download_url":"https://codeload.github.com/bietkul/react-reactive-form/tar.gz/refs/heads/mono-repo","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248148224,"owners_count":21055547,"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":["async-validation","asynchronous","form-builder","form-controls","form-fields","form-generator","form-validation","forms","observable","observer","react","react-forms","react-native","reactive-forms","subscription"],"created_at":"2024-01-05T20:17:14.301Z","updated_at":"2025-04-12T22:20:07.058Z","avatar_url":"https://github.com/bietkul.png","language":"JavaScript","funding_links":["https://opencollective.com/react-reactive-form"],"categories":["Components","Uncategorized"],"sub_categories":["Forms","Uncategorized"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"logo.png\" alt=\"React Native Game Engine\" height=\"120\" /\u003e\n\u003c/p\u003e\n\n# React Reactive Forms\n\n[![Build Status](https://travis-ci.org/bietkul/react-reactive-form.svg?branch=master)](https://travis-ci.org/bietkul/react-reactive-form)\n[![Backers on Open Collective](https://opencollective.com/react-reactive-form/backers/badge.svg)](#backers) \n[![Sponsors on Open Collective](https://opencollective.com/react-reactive-form/sponsors/badge.svg)](#sponsors) \n[![NPM Version](https://img.shields.io/npm/v/react-reactive-form.svg?style=flat)](https://www.npmjs.com/package/react-reactive-form)\n[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)\n\u003cimg \n    alt=\"gzip size\"\n    src=\"https://img.shields.io/badge/gzip%20size-7%20kB-brightgreen.svg\"\n  /\u003e\n\u003ca href=\"https://github.com/bietkul/react-reactive-form/pulls\"\u003e\n    \u003cimg\n      alt=\"PRs welcome\"\n      src=\"https://img.shields.io/badge/PRs-welcome-brightgreen.svg\"\n    /\u003e\n \u003c/a\u003e\n\nIt's a library inspired by the [Angular's Reactive Forms](https://angular.io/guide/reactive-forms), which allows to create a tree of form control objects in the component class and bind them with native form control elements.\n\n# Features\n\n* UI independent.\n* Zero dependencies.\n* Nested forms.\n* Subscribers for value \u0026 status changes of controls.\n* Provides a set of validators \u0026 also supports custom sync \u0026 async validators.\n* `FormGenerator` api to create large forms with less code.\n* Better form management with `FormGroup` \u0026 `FormArray` apis.\n* Customizable update strategy for better performace with large forms.\n\n# Installation\n\n```sh\nnpm install react-reactive-form --save\n```\n\n# Basic Example\n\n```js\nimport React, { Component } from 'react';\nimport {\n    FormBuilder,\n    FieldGroup,\n    FieldControl,\n    Validators,\n } from \"react-reactive-form\";\n\nconst TextInput = ({ handler, touched, hasError, meta }) =\u003e (\n  \u003cdiv\u003e\n    \u003cinput placeholder={`Enter ${meta.label}`} {...handler()}/\u003e\n    \u003cspan\u003e\n        {touched\n        \u0026\u0026 hasError(\"required\")\n        \u0026\u0026 `${meta.label} is required`}\n    \u003c/span\u003e\n  \u003c/div\u003e  \n)\nexport default class Login extends Component {\n    loginForm = FormBuilder.group({\n        username: [\"\", Validators.required],\n        password: [\"\", Validators.required],\n        rememberMe: false\n    });\n    handleReset=() =\u003e {\n        this.loginForm.reset();\n    }\n    handleSubmit=(e) =\u003e {\n        e.preventDefault();\n        console.log(\"Form values\", this.loginForm.value);\n    }\n    render() {\n        return (\n              \u003cFieldGroup\n                control={this.loginForm}\n                render={({ get, invalid }) =\u003e (\n                  \u003cform onSubmit={this.handleSubmit}\u003e\n\n                    \u003cFieldControl\n                      name=\"username\"\n                      render={TextInput}\n                      meta={{ label: \"Username\" }}\n                    /\u003e\n\n                    \u003cFieldControl\n                      name=\"password\"\n                      render={TextInput}\n                      meta={{ label: \"Password\" }}\n                    /\u003e\n\n                    \u003cFieldControl\n                      name=\"rememberMe\"\n                      render={({handler}) =\u003e (\n                        \u003cdiv\u003e\n                          \u003cinput {...handler(\"checkbox\")}/\u003e\n                        \u003c/div\u003e\n                      )}\n                    /\u003e\n                    \u003cbutton\n                      type=\"button\"\n                      onClick={this.handleReset}\n                    \u003e\n                      Reset\n                    \u003c/button\u003e\n                    \u003cbutton\n                      type=\"submit\"\n                      disabled={invalid}\n                    \u003e\n                      Submit\n                    \u003c/button\u003e\n                  \u003c/form\u003e\n                )}\n              /\u003e\n        );\n    }\n}\n```\n## Using [FormGenerator](docs/api/FormGenerator.md)\n```js\nimport React, { Component } from 'react';\nimport {\n    Validators,\n    FormGenerator\n } from \"react-reactive-form\";\n// Input component\nconst TextInput = ({ handler, touched, hasError, meta }) =\u003e (\n  \u003cdiv\u003e\n    \u003cinput placeholder={`Enter ${meta.label}`} {...handler()}/\u003e\n    \u003cspan\u003e\n        {touched\n        \u0026\u0026 hasError(\"required\")\n        \u0026\u0026 `${meta.label} is required`}\n    \u003c/span\u003e\n  \u003c/div\u003e  \n)\n// Checkbox component\nconst CheckBox = ({ handler }) =\u003e (\n    \u003cdiv\u003e\n      \u003cinput {...handler(\"checkbox\")}/\u003e\n    \u003c/div\u003e\n  )\n// Field config to configure form\nconst fieldConfig = {\n    controls: {\n        username: {\n            options: {\n                validators: Validators.required\n            },\n            render: TextInput,\n            meta: { label: \"Username\" }\n        },\n        password: {\n            options: {\n                validators: Validators.required\n            },\n            render: TextInput,\n            meta: { label: \"Password\" }\n        },\n        rememberMe: {\n            render: CheckBox\n        },\n        $field_0: {\n            isStatic: false,\n            render: ({ invalid, meta: { handleReset } }) =\u003e (\n                \u003cdiv\u003e\n                    \u003cbutton\n                      type=\"button\"\n                      onClick={handleReset}\n                    \u003e\n                      Reset\n                    \u003c/button\u003e\n                    \u003cbutton\n                      type=\"submit\"\n                      disabled={invalid}\n                    \u003e\n                      Submit\n                    \u003c/button\u003e\n                \u003c/div\u003e\n            )\n        }\n    },\n}\nexport default class Login extends Component {\n    handleReset=() =\u003e {\n        this.loginForm.reset();\n    }\n    handleSubmit=(e) =\u003e {\n        e.preventDefault();\n        console.log(\"Form values\", this.loginForm.value);\n    }\n    setForm = (form) =\u003e {\n        this.loginForm = form;\n        this.loginForm.meta = {\n            handleReset: this.handleReset\n        }\n    }\n    render() {\n        return (\n            \u003cform onSubmit={this.handleSubmit}\u003e\n                \u003cFormGenerator\n                    onMount={this.setForm}\n                    fieldConfig={fieldConfig}\n                /\u003e\n            \u003c/form\u003e\n        );\n    }\n}\n```\n## Add Controls Dynamically\n\nYou can also create controls without even initializing the group control object with the help of new react form components ( [FieldGroup](docs/api/FieldGroup.md), [FieldControl](docs/api/FieldControl.md), [FieldArray](docs/api/FieldArray.md)).\n\n```js\nimport React, { Component } from 'react'\nimport { FieldGroup, FieldControl, Validators } from 'react-reactive-form'\n\nexport default class Login extends Component {\n  handleSubmit = (e, value) =\u003e {\n    console.log('Form values', value)\n    e.preventDefault()\n  }\n  render() {\n    return (\n      \u003cFieldGroup\n        render={({ get, invalid, reset, value }) =\u003e (\n          \u003cform onSubmit={e =\u003e this.handleSubmit(e, value)}\u003e\n            \u003cFieldControl\n              name=\"username\"\n              options={{ validators: Validators.required }}\n              render={({ handler, touched, hasError }) =\u003e (\n                \u003cdiv\u003e\n                  \u003cinput {...handler()} /\u003e\n                  \u003cspan\u003e\n                    {touched \u0026\u0026 hasError('required') \u0026\u0026 'Username is required'}\n                  \u003c/span\u003e\n                \u003c/div\u003e\n              )}\n            /\u003e\n            \u003cFieldControl\n              name=\"password\"\n              options={{ validators: Validators.required }}\n              render={({ handler, touched, hasError }) =\u003e (\n                \u003cdiv\u003e\n                  \u003cinput {...handler()} /\u003e\n                  \u003cspan\u003e\n                    {touched \u0026\u0026 hasError('required') \u0026\u0026 'Password is required'}\n                  \u003c/span\u003e\n                \u003c/div\u003e\n              )}\n            /\u003e\n            \u003cFieldControl\n              name=\"rememberMe\"\n              render={({ handler }) =\u003e (\n                \u003cdiv\u003e\n                  \u003cinput {...handler('checkbox')} /\u003e\n                \u003c/div\u003e\n              )}\n            /\u003e\n            \u003cbutton type=\"button\" onClick={() =\u003e reset()}\u003e\n              Reset\n            \u003c/button\u003e\n            \u003cbutton type=\"submit\" disabled={invalid}\u003e\n              Submit\n            \u003c/button\u003e\n          \u003c/form\u003e\n        )}\n      /\u003e\n    )\n  }\n}\n```\n\n\u003cb\u003eSo, it's not mandatory that you need to define your control separately but if you want a better control over your form state then you should do that, if your controls are dynamic then you can also initalize the empty group control and add the controls later.\nSee the example:\u003c/b\u003e\n\n```js\nimport React, { Component } from 'react'\nimport {\n  FormBuilder,\n  FieldGroup,\n  FieldControl,\n  Validators\n} from 'react-reactive-form'\n\nexport default class Login extends Component {\n  // Initialize the empty group control\n  loginForm = FormBuilder.group({})\n\n  handleReset = e =\u003e {\n    this.loginForm.reset()\n  }\n  handleSubmit = e =\u003e {\n    console.log('Form values', this.loginForm.value)\n    e.preventDefault()\n  }\n  render() {\n    return (\n      \u003cFieldGroup\n        control={this.loginForm}\n        render={({ get, invalid, reset, value }) =\u003e (\n          \u003cform onSubmit={this.handleSubmit}\u003e\n            \u003cFieldControl\n              name=\"username\"\n              options={{ validators: Validators.required }}\n              render={({ handler, touched, hasError }) =\u003e (\n                \u003cdiv\u003e\n                  \u003cinput {...handler()} /\u003e\n                  \u003cspan\u003e\n                    {touched \u0026\u0026 hasError('required') \u0026\u0026 'Username is required'}\n                  \u003c/span\u003e\n                \u003c/div\u003e\n              )}\n            /\u003e\n            \u003cFieldControl\n              name=\"password\"\n              options={{ validators: Validators.required }}\n              render={({ handler, touched, hasError }) =\u003e (\n                \u003cdiv\u003e\n                  \u003cinput {...handler()} /\u003e\n                  \u003cspan\u003e\n                    {touched \u0026\u0026 hasError('required') \u0026\u0026 'Password is required'}\n                  \u003c/span\u003e\n                \u003c/div\u003e\n              )}\n            /\u003e\n            \u003cFieldControl\n              name=\"rememberMe\"\n              render={({ handler }) =\u003e (\n                \u003cdiv\u003e\n                  \u003cinput {...handler('checkbox')} /\u003e\n                \u003c/div\u003e\n              )}\n            /\u003e\n            \u003cbutton type=\"button\" onClick={this.handleReset}\u003e\n              Reset\n            \u003c/button\u003e\n            \u003cbutton type=\"submit\" disabled={invalid}\u003e\n              Submit\n            \u003c/button\u003e\n          \u003c/form\u003e\n        )}\n      /\u003e\n    )\n  }\n}\n```\n\n# Documentation\n\n* [Getting Started](docs)\n* [API](docs/api/)\n\n# Code Sandboxes\n  Try out `react-reactive-forms` in these sandbox versions of the Examples.\n* [Simple Form](https://codesandbox.io/s/4rxokpr270)\n* [Simple Form With FormGenerator](https://codesandbox.io/s/jpkjny836v)\n* [Sync \u0026 Async Validation](https://codesandbox.io/s/qq8xq7j2w)\n* [User Registeration Form With Nested Forms](https://codesandbox.io/s/p2rqmr8qk7)\n* [Form Array With Dynamic Controls](https://codesandbox.io/s/nw9wxw2nvl)\n* [Update On Submit](https://codesandbox.io/s/3qk1ly16j1)\n* [Multi-page Wizard Form](https://codesandbox.io/s/136340om74)\n\n\n# FAQ\n\n### How is it different from other form libraries?\n\nReact has many libraries which works on the form logic, but here are some concerns with these:\n\n#### Code Complexity\nIf you’re using the redux-form then you should know the pain, for just a two field login form you’d to write the store logic.In RRF you can see that how simple is to deal with simple and complex forms.\n\n`And one of the awesome thing is that you can just write your form controls logic anywhere in your application.`\n\n#### Dependencies\nMany libraries come with dependencies for e.g redux is required for redux-form, So what If I’m using another state management or not event using any.\nAccording to Dan Abramov, form state is inherently ephemeral and local, so tracking it in Redux (or any kind of Flux library) is unnecessary.\nRRF comes with `zero` dependency, So it’s totally up to you that how you want to save your form state if needed.\n\n#### Performance\nNow that’s a big problem with almost all libraries when you're dealing with large forms.\n\nHow RRF does solve performance issues ?\n- It uses subscription to update the components so rather updating all the fields on every input changes, it only update the particular field for which the state change takes place.\n- RRF has a nice option to define that when(blur, submit or change) to update your form's state by using the `updateOn` property.\n\n#### Dynamic Changes\nWith the help of subscribers it's pretty easy to listen for a particular state changes and modify the controls accordingly.\n\n\n### What are `value` and `status` changes subscribers?\n\nRRF uses inbuilt `Subject`, A `Subject` is an object with the method next(v).To feed a new value to the Subject,RRF just calls the next(theValue), and it will be multicasted to the Observers registered to listen to the Subject.\nSo basically it provides three subjects for each AbstractControl `valueChanges`, `statusChanges` and `stateChanges` and additional two subjects for FormControl ( `onValueChanges`, `onBlurChanges`)\nYou can register an observer to a particular Subject to do some actions whenever some particular changes happen.\n\nExample:\n\n```ts\ncomponentDidMount() {\n  this.myForm.get(“gender”).valueChanges.subscribe((value) =\u003e {\n    // do something\n  })\n}\n```\nCheckout the [Basic usage guide](docs) for more details.\n\n### How the Field components work?\n\nField components are subscribed to the state changes of a particular control which means that it’ll re-render the component only when it’s state changes disregarding of other field changes.You can also implement your custom wrappers by using the stateChanges `Subject`.\n\n### How updateOn feature works?\n\nIts an another performance booster in RRF, it just holds the computation needed to be made after every keystroke or value changes until you want to execute.It has three options `change`(default), `blur` and `submit`, you can define all of them at both field and record level.\n\n### Is this library compatible with React Native?\n\nYes, this library works with react-native also, currently it supports react-native `TextInput` and `Switch` component.\n\n### Note: \nIf you're using react-native then please add the following line of code in `index.js` of your project to avoid error in android devices.\n\n```js\nimport \"core-js/es6/symbol\";\nimport \"core-js/fn/symbol/iterator\";\n```\n\n\nLet's make React Reactive Forms better! If you're interested in helping, all contributions are welcome and appreciated.\n\nAnd don't forget to star the repo, I will ensure more frequent updates! Thanks!\n\n## Contributors\n\nThis project exists thanks to all the people who contribute. \n\u003ca href=\"https://github.com/bietkul/react-reactive-form/graphs/contributors\"\u003e\u003cimg src=\"https://opencollective.com/react-reactive-form/contributors.svg?width=890\u0026button=false\" /\u003e\u003c/a\u003e\n\n\n## Backers\n\nThank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/react-reactive-form#backer)]\n\n\u003ca href=\"https://opencollective.com/react-reactive-form#backers\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/react-reactive-form/backers.svg?width=890\"\u003e\u003c/a\u003e\n\n\n## Sponsors\n\nSupport this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/react-reactive-form#sponsor)]\n\n\u003ca href=\"https://opencollective.com/react-reactive-form/sponsor/0/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/react-reactive-form/sponsor/0/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/react-reactive-form/sponsor/1/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/react-reactive-form/sponsor/1/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/react-reactive-form/sponsor/2/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/react-reactive-form/sponsor/2/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/react-reactive-form/sponsor/3/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/react-reactive-form/sponsor/3/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/react-reactive-form/sponsor/4/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/react-reactive-form/sponsor/4/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/react-reactive-form/sponsor/5/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/react-reactive-form/sponsor/5/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/react-reactive-form/sponsor/6/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/react-reactive-form/sponsor/6/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/react-reactive-form/sponsor/7/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/react-reactive-form/sponsor/7/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/react-reactive-form/sponsor/8/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/react-reactive-form/sponsor/8/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/react-reactive-form/sponsor/9/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/react-reactive-form/sponsor/9/avatar.svg\"\u003e\u003c/a\u003e\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbietkul%2Freact-reactive-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbietkul%2Freact-reactive-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbietkul%2Freact-reactive-form/lists"}