{"id":21588935,"url":"https://github.com/cantonjs/react-form-mobx","last_synced_at":"2025-06-27T21:31:19.988Z","repository":{"id":77652047,"uuid":"135319877","full_name":"cantonjs/react-form-mobx","owner":"cantonjs","description":"🗄 Declarative Form components for React, built on top of MobX","archived":false,"fork":false,"pushed_at":"2018-10-26T10:45:24.000Z","size":328,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-17T12:44:57.926Z","etag":null,"topics":["array","form","form-data","mobx","nested-objects","react","react-component","validation"],"latest_commit_sha":null,"homepage":"https://codesandbox.io/s/52v7y2v304","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/cantonjs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-05-29T15:54:39.000Z","updated_at":"2019-08-23T03:13:33.000Z","dependencies_parsed_at":null,"dependency_job_id":"e981e65a-0c10-4e49-a4ad-ad2b077b23ef","html_url":"https://github.com/cantonjs/react-form-mobx","commit_stats":{"total_commits":165,"total_committers":1,"mean_commits":165.0,"dds":0.0,"last_synced_commit":"f81793ec450b4d04874a24285a1ad5ec273d807f"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cantonjs/react-form-mobx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cantonjs%2Freact-form-mobx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cantonjs%2Freact-form-mobx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cantonjs%2Freact-form-mobx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cantonjs%2Freact-form-mobx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cantonjs","download_url":"https://codeload.github.com/cantonjs/react-form-mobx/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cantonjs%2Freact-form-mobx/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262334837,"owners_count":23295497,"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":["array","form","form-data","mobx","nested-objects","react","react-component","validation"],"created_at":"2024-11-24T16:11:58.709Z","updated_at":"2025-06-27T21:31:19.871Z","avatar_url":"https://github.com/cantonjs.png","language":"JavaScript","readme":"# react-form-mobx\n\n[![CircleCI](https://circleci.com/gh/cantonjs/react-form-mobx.svg?style=shield)](https://circleci.com/gh/cantonjs/react-form-mobx)\n[![Build Status](https://travis-ci.org/cantonjs/react-form-mobx.svg?branch=master)](https://travis-ci.org/cantonjs/react-form-mobx)\n[![Coverage Status](https://coveralls.io/repos/github/cantonjs/react-form-mobx/badge.svg?branch=master)](https://coveralls.io/github/cantonjs/react-form-mobx?branch=master)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com)\n[![License](https://img.shields.io/badge/license-MIT_License-brightgreen.svg?style=flat)](https://github.com/cantonjs/react-form-mobx/blob/master/LICENSE.md)\n\nDeclarative Form components for [React](https://reactjs.org/), built on top of [MobX](https://mobx.js.org/)\n\n![screenshot](/.github/screenshot.png)\n\n## Table of Contents\n\n- [Table of Contents](#table-of-contents)\n- [Philosophy](#philosophy)\n  - [Features Included](#features-included)\n  - [Features NOT Included](#features-not-included)\n- [Live Demo](#live-demo)\n- [Getting Started](#getting-started)\n  - [Installing](#installing)\n  - [Usage](#usage)\n- [Advanced Guides](#advanced-guides)\n  - [Dynamic Array Items](#dynamic-array-items)\n  - [Creating Custom Input Component](#creating-custom-input-component)\n- [References](#references)\n  - [Form Component](#form-component)\n  - [Input Components](#input-components)\n  - [ObjectOf Component](#objectof-component)\n  - [ArrayOf Component](#arrayof-component)\n  - [Submit, Reset, Clear Component](#submit-reset-clear-component)\n  - [Demon Component](#demon-component)\n  - [DemonButton Component](#demonbutton-component)\n- [License](#license)\n\n## Philosophy\n\nDeclarative, just like React and HTML\n\n### Features Included\n\n- Support nested objects and arrays\n- Easy to create custom Input (or Select, Checkbox, Radio, etc) components\n- Easy to push, update or remove array items\n- Built-in validations (eg `required`, `pattern`, `enum`, etc)\n- Built-in formats (eg `integer`, `number`, `boolean`, etc)\n- Support data transformers / filters\n\n### Features NOT Included\n\n- No styles, just the original appearance, but you could add style easily\n- No HTTP requests, but you could choose any HTTP request library you like\n\n## Live Demo\n\n[Live demo on codesandbox](https://codesandbox.io/s/52v7y2v304)\n\n## Getting Started\n\n### Installing\n\n```bash\nyarn add react-form-mobx\n```\n\nYou may also need to install `react`, `mobx` and `mobx-react`\n\n```bash\nyarn add react mobx mobx-react react-form-mobx\n```\n\n\n### Usage\n\n```jsx\nimport React, { Component } from 'react';\nimport { Form, Input, ObjectOf } from 'react-form-mobx';\n\nexport default class MyFriend extends Component {\n  myData = {\n    name: 'Luke Skywalker',\n    height: 172,\n    colors: {\n      hair: 'blond',\n      skin: 'fair',\n    },\n  },\n\n  handleSubmit = (data) =\u003e {\n    console.log('data', data);\n  };\n\n  render() {\n    return (\n      \u003cForm value={this.myData} onSubmit={this.handleSubmit}\u003e\n        \u003cInput name=\"name\" /\u003e\n        \u003cInput name=\"height\" format=\"number\" /\u003e\n        \u003cObjectOf name=\"colors\"\u003e\n          \u003cInput name=\"hair\" /\u003e\n          \u003cInput name=\"skin\" /\u003e\n        \u003c/ObjectOf\u003e\n      \u003c/Form\u003e\n    );\n  }\n}\n```\n\n## Advanced Guides\n\n### Dynamic Array Items\n\n```jsx\nimport React, { Component } from 'react';\nimport { Form, Input, ArrayOf } from 'react-form-mobx';\n\nexport default class MyFriend extends Component {\n  myData = {\n    name: 'Luke Skywalker',\n    starships: ['X-wing', 'Imperial shuttle'],\n  },\n\n  handleSubmit = (data) =\u003e {\n    console.log('data', data);\n  };\n\n  render() {\n    return (\n      \u003cForm value={this.myData} onSubmit={this.handleSubmit}\u003e\n        \u003cInput name=\"name\" /\u003e\n        \u003cArrayOf name=\"starships\"\u003e\n          {(starships, { push, removeBy }) =\u003e\n            \u003cdiv\u003e\n              {starships.map((starship) =\u003e\n                \u003cspan key={starship}\u003e\n                  \u003cInput name={starship} /\u003e\n                  \u003cbutton type=\"button\" onClick={removeBy(starship)}\u003eRemove\u003c/button\u003e\n                \u003c/span\u003e\n              )}\n              \u003cbutton type=\"button\" onClick={push}\u003eAdd Starship\u003c/button\u003e\n            \u003c/div\u003e\n          }\n        \u003c/ArrayOf\u003e\n      \u003c/Form\u003e\n    );\n  }\n}\n```\n\n### Creating Custom Input Component\n\n**MyInput.js**\n\n```jsx\nimport React, { Component } from \"react\";\nimport { Demon } from \"react-form-mobx\";\n\nexport default class MyInput extends Component {\n  render() {\n    return (\n      \u003cDemon forwardedProps={this.props}\u003e\n        {(props, { isInvalid, errorMessage }) =\u003e (\n          \u003clabel\u003e\n            \u003cinput\n              style={{ borderColor: isInvalid ? \"red\" : \"green\" }}\n              {...props}\n            /\u003e\n            {isInvalid \u0026\u0026 \u003cspan style={{ color: \"red\" }}\u003e{errorMessage}\u003c/span\u003e}\n          \u003c/label\u003e\n        )}\n      \u003c/Demon\u003e\n    );\n  }\n}\n```\n\n**MyApp.js**\n\n```jsx\nimport React, { Component } from \"react\";\nimport { Form } from \"react-form-mobx\";\nimport MyInput from \"./MyInput\";\n\nexport default class MyApp extends Component {\n  render() {\n    return (\n      \u003cForm value={this.myData}\u003e\n        \u003cMyInput name=\"name\" /\u003e\n        {/* ... */}\n      \u003c/Form\u003e\n    );\n  }\n}\n```\n\n## References\n\n### Form Component\n\n```jsx\nimport { Form } from 'react-form-mobx';\n```\n\nForm component, just like HTML `form` component.\n\n#### Props\n\n| Property      | Description                                                         | Type     | Default |\n| ------------- | ------------------------------------------------------------------- | -------- | ------- |\n| value         | Form data                                                           | Object   | `{}`    |\n| onSubmit      | Defines a function will be called when form submit                  | Function |         |\n| onValid       | Defines a function will be called when form is valid                | Function |         |\n| onInvalid     | Defines a function will be called when form is invalid              | Function |         |\n| onValidChange | Defines a function will be called when form valid status changed    | Function |         |\n| onChange      | Defines a function will be called when form data changed            | Function |         |\n| inputFilter   | Defines a filter function will be called when providing a new value | Function |         |\n| outputFilter  | Defines a filter function will be called when getting output value  | Function |         |\n\n### Input Components\n\n```jsx\nimport { Input, Checkbox, Radio, Select, TextArea } from 'react-form-mobx';\n```\n\nThese Input Components mean `Input`, `Checkbox`, `Radio`, `Select`, `TextArea` or other custom input components created by `Demon`.\n\n#### Props\n\n| Property         | Description                                                                  | Type                                                                 | Default |\n| ---------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------- | ------- |\n| name             | Field name                                                                   | String `Required`                                                    |         |\n| defaultValue     | Default value when value is empty                                            | Any                                                                  |         |\n| defaultChecked   | Default checked, only work in checkable components (eg: `Checkbox`, `Radio`) | Boolean                                                              |         |\n| format           | Data format                                                                  | \"integer\", \"number\", \"string\", \"boolean\", \"date\", \"time\", \"dateTime\" |         |\n| required         | Indicates whether field is required                                          | Boolean                                                              | `false` |\n| enum             | Validate a value from a list of possible values                              | Array of `String`                                                    | `[]`    |\n| pattern          | Validate from a regular expression                                           | RegExp                                                               |         |\n| maxLength        | Validate a max length of the field                                           | Number                                                               |         |\n| minLength        | Validate a min length of the field                                           | Number                                                               |         |\n| maximum          | Validate if the field is less than or exactly equal to \"maximum\"             | Number                                                               |         |\n| exclusiveMaximum | Validate if the field is less than (not equal to) \"exclusiveMaximum\"         | Number                                                               |         |\n| minimum          | Validate if the field is greater than or exactly equal to \"minimum\"          | Number                                                               |         |\n| exclusiveMinimum | Validate if the field is greater than or exactly equal to \"exclusiveMinimum\" | Number                                                               |         |\n| validation       | Defines a validator function, should throw error if invalid                  | Function                                                             |         |\n| inputFilter      | Defines a filter function will be called when providing a new value to form  | Function                                                             |         |\n| outputFilter     | Defines a filter function will be called when getting output value from form | Function                                                             |         |\n| withEmpty        | Indicates whether submit empty value or not                                  | \"auto\", `true`, `false`                                              | \"auto\"  |\n\nThe rest of the props are exactly the same as the original [DOM attributes](https://reactjs.org/docs/dom-elements.html#all-supported-html-attributes).\n\n##### Notes\n\n- `withEmpty`: If value is empty (saying `\"\"`, `undefined`, `null`, `{}` or `[]`):\n  * `\"auto\"` (Default): Will submit empty value only if pristine value is NOT empty\n  * `true`: Will submit empty value\n  * `false`: Will not submit empty value\n\n### ObjectOf Component\n\n```jsx\nimport { ObjectOf } from 'react-form-mobx';\n```\n\n`ObjectOf` component provides nested fields.\n\n#### Props\n\n| Property     | Description                                                                  | Type              | Default |\n| ------------ | ---------------------------------------------------------------------------- | ----------------- | ------- |\n| name         | Field name                                                                   | String `Required` |         |\n| children     | Nested input nodes                                                           | Node `Required`   |         |\n| onChange     | Defines a function will be called when data changed                          | Function          |         |\n| inputFilter  | Defines a filter function will be called when providing a new value to form  | Function          |         |\n| outputFilter | Defines a filter function will be called when getting output value from form | Function          |         |\n\n### ArrayOf Component\n\n```jsx\nimport { ArrayOf } from 'react-form-mobx';\n```\n\n`ArrayOf` component provides array fields, and could be push, update or remove easily.\n\n#### Props\n\n| Property     | Description                                                                  | Type                        | Default |\n| ------------ | ---------------------------------------------------------------------------- | --------------------------- | ------- |\n| name         | Field name                                                                   | String `Required`           |         |\n| children     | Nested input nodes or function child that should return a node               | Node or Function `Required` |         |\n| onChange     | Defines a function will be called when data changed                          | Function                    |         |\n| inputFilter  | Defines a filter function will be called when providing a new value to form  | Function                    |         |\n| outputFilter | Defines a filter function will be called when getting output value from form | Function                    |         |\n\n#### Function Child\n\nIf `children` prop is a callback renderer function, it will provide two arguments:\n\n- `names` \\\u003cArray\\\u003e: An array of unique names that could be used as the `key` and `name` props of chidren components\n- `helper` \\\u003cObject\\\u003e: A helper object to manipulate the array:\n  * `push()` \\\u003cFunction\\\u003e: To push a new item\n  * `remove(name)` \\\u003cFunction\\\u003e: To remove a item by `name`\n  * `removeBy(name)` \\\u003cFunction\\\u003e: To create and return a `remove(name)` currying function\n\nPlease checkout [Dynamic Array Items](#dynamic-array-items) for usage example.\n\n### Submit, Reset, Clear Component\n\n```jsx\nimport { Submit, Reset, Clear } from 'react-form-mobx';\n```\n\n- `Submit`: Just like HTML `button` component. Will emit `onSubmit()` in `Form` when click.\n- `Reset`: Just like HTML `button` component. Will reset all input values to pristine values in `Form` when click\n- `Clear`: Just like HTML `button` component. Will clear all input values in `Form` when click.\n\n#### Props\n\n| Property | Description | Type | Default |\n| -------- | ----------- | ---- | ------- |\n| children | children    | Node |         |\n\nThe rest of the props are exactly the same as the original [DOM attributes](https://reactjs.org/docs/dom-elements.html#all-supported-html-attributes).\n\n### Demon Component\n\n```jsx\nimport { Demon } from 'react-form-mobx';\n```\n\n`Demon` component is the core of creating custom input components.\n\n#### Props\n\n| Property                  | Description                                                  | Type                | Default                            |\n| ------------------------- | ------------------------------------------------------------ | ------------------- | ---------------------------------- |\n| name                      | Field name                                                   | String `Required`   |                                    |\n| children                  | Function child that should return a node                     | Function `Required` |                                    |\n| forwardedProps            | Forward props, `Demon` will decide to handle or forward them | Object              | `{}`                               |\n| checkable                 | Indicates whether the component is checkable                 | Boolean             | `false`                            |\n| getValueFromChangeEvent   | Defines a function to get `value` in `onChange` arguments    | Function            | `(ev) =\u003e ev.currentTarget.value`   |\n| getCheckedFromChangeEvent | Defines a function to get `checked` in `onChange` arguments  | Function            | `(ev) =\u003e ev.currentTarget.checked` |\n| getKeyFromKeyPressEvent   | Defines a function to get `key` in `onPress` arguments       | Function            | `(ev) =\u003e ev.key`                   |\n| propOnChange              | Defines the prop name of change event                        | String              | \"onChange\"                         |\n| propOnKeyPress            | Defines the prop name of key press event                     | String              | \"onKeyPress\"                       |\n| propOnBlur                | Defines the prop name of blur event                          | String              | \"onBlur\"                           |\n\n#### Function Child\n\n`children` prop provides two arguments:\n\n- `proxyProps` \\\u003cObject\\\u003e: Forwarded props object including `value` or `checked`, but excluding `name`, `format`, `enum` and other props only work in `Demon` component. Can be directly pass to child component (like `\u003cinput {...proxyProps} /\u003e`)\n\n- `validState` \\\u003cObject\\\u003e: Valid state helper object, including:\n  * `errorMessage` \\\u003cString\\\u003e: Error message. Would be empty if the status is valid\n  * `isValid` \\\u003cBoolean\\\u003e: Would be true if the status is valid\n  * `isInvalid` \\\u003cBoolean\\\u003e: Would be true if the status is invalid\n  * `isTouched` \\\u003cBoolean\\\u003e: Is touched or not. Useful if you don't want to show `errorMessage` when field is not touched\n\n#### Proxied Props\n\nBy default, `onChange`, `onKeyPress`, `onBlur` props will be proxied.\n\n- `onChange`: `Demon` need to get the changed `value` or `checked` from the `change` event object to update value. You can change the getting function by setting `getValueFromChangeEvent` or `getCheckedFromChangeEvent` prop to `Demon` component.\n- `onKeyPress`: `Demon` need to get the `key` from the `keyPress` event object to decide to submit. You can change the getting function by settting `propOnKeyPress` prop to `Demon` component\n- `onBlur`: `Demon` need to listen to the `blur` event to set `isTouched` to `true`\n\nPlease checkout [Creating Custom Input Component](#creating-custom-input-component) for usage example.\n\n### DemonButton Component\n\n```jsx\nimport { DemonButton } from 'react-form-mobx';\n```\n\n`DemonButton` component is the core of creating custom button (Submit, Reset or Clear) components.\n\n#### Props\n\n| Property                | Description                                                        | Type                       | Default          |\n| ----------------------- | ------------------------------------------------------------------ | -------------------------- | ---------------- |\n| children                | Function child that should return a node                           | Function `Required`        |                  |\n| type                    | Button type                                                        | \"submit\", \"reset\", \"clear\" | \"submit\"         |\n| forwardedProps          | Forward props, `DemonButton` will decide to handle or forward them | Object                     | `{}`             |\n| getKeyFromKeyPressEvent | Defines a function to get `key` in `onPress` arguments             | Function                   | `(ev) =\u003e ev.key` |\n| propOnKeyPress          | Defines the prop name of key press event                           | String                     | \"onKeyPress\"     |\n\n#### Function Child\n\n`children` prop provides one argument:\n\n- `proxyProps` \\\u003cObject\\\u003e: Forwarded props object. Can be directly pass to child component (like `\u003cbutton {...proxyProps} type=\"button\" /\u003e`)\n\n## License\n\nMIT\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcantonjs%2Freact-form-mobx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcantonjs%2Freact-form-mobx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcantonjs%2Freact-form-mobx/lists"}