{"id":14384988,"url":"https://github.com/ffxsam/formous","last_synced_at":"2025-04-06T23:17:43.051Z","repository":{"id":57240611,"uuid":"62432700","full_name":"ffxsam/formous","owner":"ffxsam","description":"Simple and elegant form-handling for React - ABANDONWARE","archived":false,"fork":false,"pushed_at":"2018-08-27T16:20:04.000Z","size":74,"stargazers_count":327,"open_issues_count":5,"forks_count":3,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-03-30T21:08:03.427Z","etag":null,"topics":["forms","react"],"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/ffxsam.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}},"created_at":"2016-07-02T03:46:00.000Z","updated_at":"2024-06-24T08:26:40.000Z","dependencies_parsed_at":"2022-08-30T00:10:40.358Z","dependency_job_id":null,"html_url":"https://github.com/ffxsam/formous","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ffxsam%2Fformous","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ffxsam%2Fformous/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ffxsam%2Fformous/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ffxsam%2Fformous/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ffxsam","download_url":"https://codeload.github.com/ffxsam/formous/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247563941,"owners_count":20958971,"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":["forms","react"],"created_at":"2024-08-28T18:01:50.474Z","updated_at":"2025-04-06T23:17:43.030Z","avatar_url":"https://github.com/ffxsam.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# Formous [![Build Status](https://travis-ci.org/ffxsam/formous.svg?branch=master)](https://travis-ci.org/ffxsam/formous)\n\n## ***NOTE: This repository is abandonware. PRs will not be accepted.***\n\n### Simple and elegant form-handling for React\n\nFormous strives to be a *simple*, elegant solution to handling forms in React. Formous's features and benefits:\n\n* Allows easy testing/validation of fields.\n* Can differentiate between critical (blocker) field errors and warnings (can still submit the form).\n* Super simple to use. No over-engineering here!\n* Unopinionated when it comes to UI. Formous just tells you what you need to know and lets you handle the rest.\n\n## Contents\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Usage](#usage)\n  - [Formous Options](#formous-options)\n    - [Test Object Structure](#test-object-structure)\n    - [Test-Chaining](#test-chaining)\n  - [Handling Form Submission](#handling-form-submission)\n- [Reference](#reference)\n  - [Formous-Supplied Props](#formous-supplied-props)\n    - [`clearForm: Function`](#clearform-function)\n    - [`fields: Object`](#fields-object)\n    - [`formSubmit: (handler: Function) =\u003e Function`](#formsubmit-handler-function--function)\n    - [`formState: Object`](#formstate-object)\n    - [`setDefaultValues: (fields: Object)`](#setdefaultvalues-fields-object)\n  - [Formous Wrapper Options](#formous-wrapper-options)\n    - [`fields: Object`](#fields-object-1)\n- [Planned Features](#planned-features)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Installation\n\n    npm i --save formous\n\n## Quick Start\n\nUse the code snippet below as an example to help you get started right away.\n\n```js\nimport React, { Component } from 'react';\nimport Formous from 'formous';\n\nclass ErrorText extends Component {\n  render() {\n    return \u003cdiv style={{ color: '#f00' }}\u003e\n      {this.props.errorText}\n    \u003c/div\u003e\n  }\n}\n\nclass MyComponent extends Component {\n  componentWillReceiveProps(nextProps) {\n  \t// Set default form values (might be appropriate in a different method\n  \tthis.props.setDefaultValues({\n  \t  age: 33,\n  \t  name: 'Sir Fluffalot',\n  \t});\n  }\n  \n  handleSubmit(formStatus, fields) {\n    if (!formStatus.touched) {\n      alert('Please fill out the form.');\n      return;\n    }\n\n    if (!formStatus.valid) {\n      alert('Please address the errors in the form.');\n      return;\n    }\n\n    // All good! Do something with fields.name.value and fields.age.value\n    console.log(formStatus, fields);\n  }\n\n  render() {\n    const {\n      fields: { age, name },\n      formSubmit,\n    } = this.props;\n\n    return \u003cdiv\u003e\n      \u003cform onSubmit={formSubmit(this.handleSubmit)}\u003e\n        \u003cdiv\u003e\n          \u003cinput\n            placeholder=\"Name\"\n            type=\"text\"\n            value={name.value}\n            { ...name.events }\n          /\u003e\n          \u003cErrorText { ...name.failProps } /\u003e\n        \u003c/div\u003e\n        \u003cdiv\u003e\n          \u003cinput\n            placeholder=\"Age\"\n            type=\"text\"\n            value={age.value}\n            { ...age.events }\n          /\u003e\n          \u003cErrorText { ...age.failProps } /\u003e\n        \u003c/div\u003e\n        \u003cdiv\u003e\n          \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n        \u003c/div\u003e\n      \u003c/form\u003e\n    \u003c/div\u003e\n  }\n}\n\nconst formousOptions = {\n  fields: {\n    name: {\n      name: 'name',\n      tests: [\n        {\n          critical: true,\n          failProps: {\n            errorText: 'Name is required.',\n          },\n          test(value) {\n            return value !== '';\n          },\n        }\n      ],\n    },\n\n    age: {\n      name: 'age',\n      tests: [\n        {\n          critical: true,\n          failProps: {\n            errorText: 'Age should be a number.',\n          },\n          test(value) {\n            return /^\\d*$/.test(value);\n          },\n        },\n        {\n          critical: false,\n          failProps: {\n            errorText: 'Are you sure you\\'re that old? :o',\n          },\n          test(value) {\n            return +value \u003c 120;\n          },\n        },\n      ],\n    },\n  },\n};\n\nexport default Formous(formousOptions)(MyComponent)\n```\n\n## Usage\n\nFormous is a [higher-order component](https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750) that you can use to wrap your component in order to supply it with field validation, error notifications, and form submission handling.\n\nImport Formous at the top of your component's code:\n\n```js\nimport Formous from 'formous';\n```\n\nAnd at the bottom:\n\n```js\nexport default Formous(options)(MyComponent)\n```\n\nWe'll get into the the `options` in a bit. Wrapping your component with Formous provides extra props (such as `fields`) that you'll use to apply event-handlers and error-reporting to any JSX elements you wish. Let's say you have username and password fields in your component that you want Formous to handle. That could look like this:\n\n```js\nconst { username, password } = this.props.fields;\n\nreturn \u003cdiv\u003e\n  \u003cdiv\u003e\n    Username:\n    \u003cinput\n      type=\"text\"\n      value={username.value}\n      { ...username.events }\n    /\u003e\n  \u003c/div\u003e\n\n  \u003cdiv\u003e\n    Password:\n    \u003cinput\n      type=\"password\"\n      value={password.value}\n      { ...password.events }\n    /\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\nThis applies `onBlur`, `onChange,` and `onFocus` handlers to the appropriate elements. These will become [controlled inputs](https://facebook.github.io/react/docs/forms.html#controlled-components), so be sure to include the `value={...}` attribute!\n\nFormous was built to work with any UI framework (or none at all). So if, for example, you happen to be using Material UI, this would work just as well:\n\n```js\n\u003cTextField\n  floatingLabelText=\"Email\"\n  spellCheck={false}\n  value={email.value}\n  { ...email.events }\n/\u003e\n```\n\n### Formous Options\n\nThe `Formous` wrapper component requires a single argument, which is an object literal containing information about your fields, including tests to run in order to perform validation. The general format for the options is as follows:\n\n```js\nconst options = {\n  fields: {\n    field1: {\n      name: 'field1', // must match the property name\n      tests: [\n        {\n          critical: true, // is this test fails, it's a blocker to submitting the form\n          failProps: {\n            // the props that should be applied to a given element if the test fails\n          },\n          test(value, fields) {\n            /*\n             * value: string\n             *   The value of this field at the time the test is run (on blur)\n             * fields: Object\n             *   Access to all the values of the fields in this options object.\n             *   This is used for side-effect/chained tests.\n             */\n\n            // return true if value is good, otherwise return false\n          },\n        },\n      ],\n      alsoTest: [\n        // Array of field names to test after this field is tested\n      ],\n    },\n\n    field2: {\n      // ...\n    },\n  },\n};\n```\n\n#### Test Object Structure\n\nLet's cover the test object properties in detail.\n\n**`critical: boolean`**\n\nIf this test is critical and the test fails, it's considered a blocker. This means two things: #1, the form will be considered to be in an invalid state, and #2, any subsequent tests for this field will not be run.\n\nIf the test is not critical, it's considered a warning and the form will still be in a valid state. You could use this, for example, to warn someone that their password is not strong enough but you don't want to prevent form submission.\n\nMake sure critical tests are ***always*** placed above non-critical tests! Only a single error can be returned from Formous, so if a non-critical test is above a critical one and it fails, no more tests in the list will be performed.\n\n**`failProps: Object`**\n\nThis object contains properties that you'd want to apply to a particular element in order to indicate to the user that the field in question failed validation. Being a collection of props, this allows the developer more freedom in handling how they want to display an error.\n\nFor instance, in Material UI, a `TextField` component can accept the props `errorText` and `errorStyle` to display an error. So in Formous, we might specify `failProps` as such:\n\n```js\nfailProps: {\n  errorStyle: { color: '#f00' },\n  errorText: 'Email is required.',\n},\n```\n\nThen we just make sure these props get applied to the `TextField` element:\n\n```js\n\u003cTextField\n  floatingLabelText=\"Email\"\n  spellCheck={false}\n  value={email.value}\n  { ...email.events }\n  { ...email.failProps }\n/\u003e\n```\n\n**`test: (value: string, fields: Object) =\u003e boolean`**\n\nThe `test` function is called whenever the field's `onBlur` event is triggered. Two arguments are passed into `test`: the first is the value of the field at the time of the blur event, and the second is an object containing all the fields that Formous is managing. This is useful for [test-chaining](#test-chaining).\n\nSimply perform whatever test you need on the given value, and return `true` if it's valid, or `false` if not.\n\n#### Test-Chaining\n\nFormous supports test-chaining, via the `alsoTest` array, which allows you to test related fields after the current field has passed its own tests. This is useful in cases where one field relies upon another, such as when a password field has been filled out but its corresponding confirmation field has not. In this example, when the user fills out the password field and tabs out of it, you wouldn't necessarily want the confirmation field to display an error because they haven't even gotten to that point yet. This is why Formous will quietly mark the confirmation field as invalid without returning an error. This effectively marks the entire form as invalid, but gives the user a chance to finish filling it out. See the example below.\n\n```js\nconst passwordFilled = {\n  critical: true,\n  failProps: {\n    errorStyle,\n    errorText: 'Password is too short.',\n  },\n  test(value) {\n    return value === '' || value.length \u003e= 4;\n  },\n};\n\nconst options = {\n  fields: {\n    password: {\n      name: 'password',\n      tests: [\n        passwordFilled,\n      ],\n      alsoTest: ['passwordConfirm'],\n    },\n\n    passwordConfirm: {\n      name: 'passwordConfirm',\n      tests: [\n        passwordFilled,\n        {\n          critical: true,\n          failProps: {\n            errorStyle,\n            errorText: 'Please confirm the password you typed above.',\n          },\n          test(value, fields) {\n            if (!fields.password) return true; // fields not populated yet\n            return fields.password.value === '' || value !== '';\n          },\n        },\n        {\n          critical: true,\n          failProps: {\n            errorStyle,\n            errorText: 'The passwords do not match.',\n          },\n          test(value, fields) {\n            if (!fields.password) return true;\n            return value === fields.password.value;\n          },\n        },\n      ],\n    },\n  },\n};\n```\n\n### Handling Form Submission\n\nFormous passes another prop into the wrapped component, called `formSubmit`. You pass `formSubmit` a single function, and it returns a bound function which should be used in your form `onSubmit` prop. For example:\n\n```js\nclass MyComponent extends Component {\n  handleSubmit(formStatus, fields) {   \n  }\n  \n  render() {\n    return \u003cdiv\u003e\n      \u003cform onSubmit={this.props.formSubmit(this.handleSubmit)}\u003e\n        {/* ... */}\n      \u003c/form\u003e\n    \u003c/div\u003e\n  }\n}\n```\n\n## Reference\n\nAll annotations use [Flow](https://flowtype.org/) syntax.\n\n### Formous-Supplied Props\n\n#### `clearForm: Function`\n\n* Call with no arguments. Sets all fields to empty.\n\n#### `fields: Object`\n\n* `\u003cfield name\u003e`\n  * `value: string` - the current value of the field\n  * `events: Object` - contains events necessary to capture field input\n  * `failProps: Object` - contains the props specified in the Formous wrapper options, or an empty object if there's no error\n\n#### `formSubmit: (handler: Function) =\u003e Function`\n\n* `handler: (formStatus: Object, fields: Object)` - the function to be called when the user attempts to submit the form\n  * `formStatus: { touched: boolean, valid: boolean }`\n    * `touched` - indicates whether the form has been \"touched\" at all (if any fields have received focus)\n    * `valid` - indicates whether the field is valid\n\n#### `formState: Object`\n\n* `touched: boolean` - whether the form has been touched (field focused)\n* `valid: boolean` - whether the form is valid\n\n#### `setDefaultValues: (fields: Object)`\n\n* `fields` - name/value pairs, e.g.:\n\n```js\nthis.props.setDefaultValues({\n  name: 'My Name',\n  age: 30,\n});\n```\n\n### Formous Wrapper Options\n\n#### `fields: Object`\n\n* `name: string` - name of the field\n* `tests: Array\u003cObject\u003e` - sequential list of tests to perform\n  * `critical: boolean` - whether the test failure is a blocker\n  * `failProps: Object` - props to pass into wrapped component in case of test failure\n  * `test: (value: string, fields: Object) =\u003e boolean` - test function\n    * `value` - the field's current value (at the time of the test)\n    * `fields` - an object containing values of all the fields in the form\n* `alsoTest: Array\u003cstring\u003e` - a list of field names to test after this field's tests are complete\n\n## Planned Features\n\n* Implement support for multi-step forms.\n* Give the ability for the `test` function to perform an async operation and report the result (as well as indicate when it's busy/done).\n* Allow for the error message to be conveyed as a simple string instead of props.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fffxsam%2Fformous","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fffxsam%2Fformous","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fffxsam%2Fformous/lists"}