{"id":13429569,"url":"https://github.com/wsmd/react-use-form-state","last_synced_at":"2025-05-15T03:04:19.540Z","repository":{"id":33219613,"uuid":"155302203","full_name":"wsmd/react-use-form-state","owner":"wsmd","description":"📄 React hook for managing forms and inputs state","archived":false,"fork":false,"pushed_at":"2023-01-04T21:38:48.000Z","size":917,"stargazers_count":936,"open_issues_count":30,"forks_count":55,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-05-15T03:03:11.761Z","etag":null,"topics":["hook","react","react-hooks","react-library","reactjs"],"latest_commit_sha":null,"homepage":"http://react-use-form-state.now.sh","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/wsmd.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":"2018-10-30T00:54:57.000Z","updated_at":"2025-03-13T02:03:02.000Z","dependencies_parsed_at":"2023-01-14T23:57:22.459Z","dependency_job_id":null,"html_url":"https://github.com/wsmd/react-use-form-state","commit_stats":null,"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wsmd%2Freact-use-form-state","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wsmd%2Freact-use-form-state/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wsmd%2Freact-use-form-state/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wsmd%2Freact-use-form-state/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wsmd","download_url":"https://codeload.github.com/wsmd/react-use-form-state/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254264750,"owners_count":22041793,"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":["hook","react","react-hooks","react-library","reactjs"],"created_at":"2024-07-31T02:00:41.872Z","updated_at":"2025-05-15T03:04:19.492Z","avatar_url":"https://github.com/wsmd.png","language":"JavaScript","funding_links":[],"categories":["Packages","JavaScript","Frontend  frameworks \u0026 libraries"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/2100222/47732577-e00e9280-dc3c-11e8-9f2f-dd290b29fd35.png\" width=\"128\"\u003e\n  \u003cbr\u003e\n  react-use-form-state\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/react-use-form-state\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/react-use-form-state.svg\" alt=\"Current Release\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/react-use-form-state\"\u003e\n    \u003cimg src=\"https://badgen.net/npm/dt/react-use-form-state\" alt=\"Downloads\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://travis-ci.org/wsmd/react-use-form-state\"\u003e\n    \u003cimg src=\"https://travis-ci.org/wsmd/react-use-form-state.svg?branch=master\" alt=\"CI Build\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://coveralls.io/github/wsmd/react-use-form-state?branch=master\"\u003e\n    \u003cimg src=\"https://coveralls.io/repos/github/wsmd/react-use-form-state/badge.svg?branch=master\" alt=\"Coverage Status\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/wsmd/react-use-form-state/blob/master/LICENSE\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/license/wsmd/react-use-form-state.svg\" alt=\"Licence\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e📖 Table of Contents\u003c/summary\u003e\n\u003cp\u003e\n\n- [Motivation](#motivation)\n- [Getting Started](#getting-started)\n- [Examples](#examples)\n  - [Basic Usage](#basic-usage)\n  - [Initial State](#initial-state)\n  - [Global Handlers](#global-handlers)\n  - [Advanced Input Options](#advanced-input-options)\n  - [Custom Input Validation](#custom-input-validation)\n  - [Check If the Form State Is Pristine](#check-if-the-form-state-is-pristine)\n  - [Without Using a `\u003cform /\u003e` Element](#without-using-a-form--element)\n  - [Labels](#labels)\n  - [Custom Controls](#custom-controls)\n  - [Updating Fields Manually](#updating-fields-manually)\n  - [Resetting The Form State](#resetting-the-form-state)\n- [Working with TypeScript](#working-with-typescript)\n- [API](#api)\n  - [`initialState`](#initialstate)\n  - [`formOptions`](#formoptions)\n    - [`formOptions.onBlur`](#formoptionsonblur)\n    - [`formOptions.onChange`](#formoptionsonchange)\n    - [`formOptions.onTouched`](#formoptionsontouched)\n    - [`formOptions.onClear`](#formoptionsonclear)\n    - [`formOptions.onReset`](#formoptionsonreset)\n    - [`formOptions.validateOnBlur`](#formoptionsvalidateonblur)\n    - [`formOptions.withIds`](#formoptionswithids)\n  - [`[formState, inputs]`](#formstate-inputs)\n    - [Form State](#form-state)\n    - [Input Types](#input-types)\n    - [Input Options](#input-options)\n- [License](#license)\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n## Motivation\n\nManaging form state in React can be a bit unwieldy sometimes. There are [plenty of great solutions](https://www.npmjs.com/search?q=react%20forms\u0026ranking=popularity) already available that make managing forms state a breeze. However, many of those solutions are opinionated, packed with tons of features that may end up not being used, and/or require shipping a few extra bytes!\n\nLuckily, the recent introduction of [React Hooks](https://reactjs.org/docs/hooks-intro.html) and the ability to write custom hooks have enabled new possibilities when it comes sharing state logic. Form state is no exception!\n\n`react-use-form-state` is a small React Hook that attempts to [simplify managing form state](#examples), using the native form input elements you are familiar with!\n\n## Getting Started\n\nTo get it started, add `react-use-form-state` to your project:\n\n```\nnpm install --save react-use-form-state\n```\n\nPlease note that `react-use-form-state` requires `react@^16.8.0` as a peer dependency.\n\n## Examples\n\n### Basic Usage\n\n```jsx\nimport { useFormState } from 'react-use-form-state';\n\nexport default function SignUpForm({ onSubmit }) {\n  const [formState, { text, email, password, radio }] = useFormState();\n\n  function handleSubmit(e) {\n    // ...\n  }\n\n  return (\n    \u003cform onSubmit={handleSubmit}\u003e\n      \u003cinput {...text('name')} /\u003e\n      \u003cinput {...email('email')} required /\u003e\n      \u003cinput {...password('password')} required minLength=\"8\" /\u003e\n      \u003cinput {...radio('plan', 'free')} /\u003e\n      \u003cinput {...radio('plan', 'premium')} /\u003e\n    \u003c/form\u003e\n  );\n}\n```\n\nFrom the example above, as the user fills in the form, the `formState` object will look something like this:\n\n```js\n{\n  values: {\n    name: 'Mary Poppins',\n    email: 'mary@example.com',\n    password: '1234',\n    plan: 'free',\n  },\n  touched: {\n    name: true,\n    email: true,\n    password: true,\n    plan: true,\n  },\n  validity: {\n    name: true,\n    email: true,\n    password: false,\n    plan: true,\n  },\n  errors: {\n    password: 'Please lengthen this text to 8 characters or more',\n  },\n  clear: Function,\n  clearField: Function,\n  reset: Function,\n  resetField: Function,\n  setField: Function,\n}\n```\n\n### Initial State\n\n`useFormState` takes an initial state object with keys matching the names of the inputs.\n\n```jsx\nexport default function RentCarForm() {\n  const [formState, { checkbox, radio, select }] = useFormState({\n    trip: 'roundtrip',\n    type: ['sedan', 'suv', 'van'],\n  });\n  return (\n    \u003cform\u003e\n      \u003cselect {...select('trip')}\u003e\n        \u003coption value=\"roundtrip\"\u003eSame Drop-off\u003c/option\u003e\n        \u003coption value=\"oneway\"\u003eDifferent Drop-off\u003c/option\u003e\n      \u003c/select\u003e\n      \u003cinput {...checkbox('type', 'sedan')} /\u003e\n      \u003cinput {...checkbox('type', 'suv')} /\u003e\n      \u003cinput {...checkbox('type', 'van')} /\u003e\n      \u003cbutton\u003eSubmit\u003c/button\u003e\n    \u003c/form\u003e\n  );\n}\n```\n\n### Global Handlers\n\n`useFormState` supports [a variety of form-level event handlers](#formoptions) that you could use to perform certain actions:\n\n```jsx\nexport default function RentCarForm() {\n  const [formState, { email, password }] = useFormState(null, {\n    onChange(e, stateValues, nextStateValues) {\n      const { name, value } = e.target;\n      console.log(`the ${name} input has changed!`);\n    },\n  });\n  return (\n    \u003c\u003e\n      \u003cinput {...text('username')} /\u003e\n      \u003cinput {...password('password')} /\u003e\n    \u003c/\u003e\n  );\n}\n```\n\n### Advanced Input Options\n\n`useFormState` provides a quick and simple API to get started with building a form and managing its state. It also supports [HTML5 form validation](https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Form_validation) out of the box.\n\n```jsx\n\u003cinput {...password('password')} required minLength=\"8\" /\u003e\n```\n\nWhile this covers that majority of validation cases, there are times when you need to attach custom event handlers or perform custom validation.\n\nFor this, all [input functions](#input-types) provide an alternate API that allows you attach input-level event handlers such as `onChange` and `onBlur`, as well as providing custom validation logic.\n\n```jsx\nexport default function SignUpForm() {\n  const [state, { text, password }] = useFormState();\n  return (\n    \u003c\u003e\n      \u003cinput {...text('username')} required /\u003e\n      \u003cinput\n        {...password({\n          name: 'password',\n          onChange: e =\u003e console.log('password input changed!'),\n          onBlur: e =\u003e console.log('password input lost focus!'),\n          validate: (value, values, e) =\u003e validatePassword(value),\n          validateOnBlur: true,\n        })}\n      /\u003e\n    \u003c/\u003e\n  );\n}\n```\n\n### Custom Input Validation\n\nThe example above [demonstrates](#advanced-input-options) how you can determine the validity of an input by passing a `validate()` method. You can also specify custom validation errors using the same method.\n\nThe input is considered **valid** if this method returns `true` or `undefined`.\n\nAny [truthy value](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) other than `true` returned from this method will make the input **invalid**. This returned value is used as a **custom validation error** that can be retrieved from [`state.errors`](#form-state).\n\nFor convenience, empty collection values such as empty objects, empty arrays, empty maps, empty sets are not considered invalidation errors, and if returned the input will be valid.\n\n```jsx\n\u003cinput\n  {...password({\n    name: 'password',\n\n    // can also return objects, arrays, etc, for more complex error objects\n    validate: (value, values, event) =\u003e {\n      if (!value.trim()) {\n        return 'Password is required';\n      }\n      if (!STRONG_PASSWORD_REGEX.test(value)) {\n        return 'Password is not strong enough';\n      }\n    },\n  })}\n/\u003e\n```\n\nIf the input's value is invalid based on the rules specified above, the form state will look similar to this:\n\n```js\n{\n  validity: {\n    password: false,\n  },\n  errors: {\n    password: 'Password is not strong enough',\n  }\n}\n```\n\nIf the `validate()` method is not specified, `useFormState` will fallback to the HTML5 constraints validation to determine the validity of the input along with the appropriate error message.\n\n### Check If the Form State Is Pristine\n\n`useFormState` exposes a `pristine` object, and an `isPristine()` helper via `formState` that you can use to check if the user has made any changes.\n\nThis can be used for a Submit button, to disable it, if there are no actual changes to the form state:\n\n```js\nfunction PristineForm() {\n  const [formState, { text, password }] = useFormState();\n  return (\n    \u003cdiv\u003e\n      \u003cinput {...text('username')} /\u003e\n      \u003cinput {...password('password')} /\u003e\n      \u003cbutton disabled={formState.isPristine()} onClick={handleSubmit}\u003e\n        Login\n      \u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\nChecking if a field is pristine is done with simple equality `===`, with some exceptions. This can be overridden per field by providing a custom `compare` function.\n\nNote that a `compare` function is **required** for [`raw`](#custom-controls) inputs, otherwise, if not specified, the `pristine` value of a `raw` input will always be set to `false` after a change.\n\n```jsx\n\u003cinput\n  {...raw({\n    name: 'userObj',\n    compare(initialValue, value) {\n      // returns a boolean indicating if the changed value is equal to the initial value\n      return isEqualDeep(initialValue, value);\n    },\n  })}\n/\u003e\n```\n\n### Without Using a `\u003cform /\u003e` Element\n\n`useFormState` is not limited to actual forms. It can be used anywhere inputs are used.\n\n```jsx\nfunction LoginForm({ onSubmit }) {\n  const [formState, { email, password }] = useFormState();\n  return (\n    \u003cdiv\u003e\n      \u003cinput {...email('email')} required /\u003e\n      \u003cinput {...password('password')} required minLength=\"8\" /\u003e\n      \u003cbutton onClick={() =\u003e onSubmit(formState)}\u003eLogin\u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Labels\n\nAs a convenience, `useFormState` provides an optional API that helps with pairing a label to a specific input.\n\nWhen [`formOptions.withIds`](#formoptionswithids) is enabled, a label can be paired to an [input](#input-types) by using `input.label()`. This will populate the label's `htmlFor` attribute for an input with the same parameters.\n\n```js\nconst [formState, { label, text, radio }] = useFormState(initialState, {\n  withIds: true, // enable automatic creation of id and htmlFor props\n});\n\nreturn (\n  \u003cform\u003e\n    \u003clabel {...label('name')}\u003eFull Name\u003c/label\u003e\n    \u003cinput {...text('name')} /\u003e\n\n    \u003clabel {...label('plan', 'free')}\u003eFree Plan\u003c/label\u003e\n    \u003cinput {...radio('plan', 'free')} /\u003e\n\n    \u003clabel {...label('plan', 'premium')}\u003ePremium Plan\u003c/label\u003e\n    \u003cinput {...radio('plan', 'premium')} /\u003e\n  \u003c/form\u003e\n);\n```\n\nNote that this will override any existing `id` prop if specified before calling the input functions. If you want the `id` to take precedence, it must be passed _after_ calling the input types like this:\n\n```jsx\n\u003cinput {...text('username')} id=\"signup-username\" /\u003e\n```\n\n### Custom Controls\n\n`useFormState` provides a `raw` type for working with controls that do not use React's [`SyntheticEvent`](https://reactjs.org/docs/events.html) system. For example, controls like [react-select](https://react-select.com/home) or [react-datepicker](https://www.npmjs.com/package/react-datepicker) have `onChange` and `value` props that expect a custom value instead of an event.\n\nTo use this, your custom component should support an `onChange()` event which takes the value as a parameter, and a `value` prop which is expected to contain the value. Note that if no initial value is given, the component will receive a `value` prop of an empty string, which might not be what you want. Therefore, you must provide an [initial value](#initial-state) for `raw()` inputs when working with custom controls.\n\n```js\nimport DatePicker from 'react-datepicker';\n\nfunction Widget() {\n  const [formState, { raw }] = useFormState({ date: new Date() });\n  return (\n    \u003c\u003e\n      \u003cDatePicker {...raw('date')} /\u003e\n    \u003c/\u003e\n  );\n}\n```\n\nYou can also provide an `onChange` option with a return value in order to map the value passed from the custom control's `onChange` to a different value in the form state.\n\n```js\nfunction Widget() {\n  const [formState, { raw }] = useFormState({ date: new Date() });\n  return (\n    \u003c\u003e\n      \u003cDatePicker\n        {...raw({\n          name: 'date',\n          onChange: date =\u003e date.toString();\n        })}\n        value={new Date(formState.date)}\n      /\u003e\n    \u003c/\u003e\n  );\n}\n```\n\nNote that `onChange()` for a `raw` value _must_ return a value.\n\nMany raw components do not support `onBlur()` correctly. For these components, you can use `touchOnChange` to mark a field as touched when it changes instead of on blur:\n\n```js\nfunction Widget() {\n  const [formState, { raw }] = useFormState({ date: new Date() });\n  return (\n    \u003c\u003e\n      \u003cCustomComponent\n        {...raw({\n          name: 'date',\n          touchOnChange: true,\n        })}\n      /\u003e\n    \u003c/\u003e\n  );\n}\n```\n\n### Updating Fields Manually\n\nThere are cases where you may want to update the value of an input manually without user interaction. To do so, the `formState.setField` method can be used.\n\n```js\nfunction Form() {\n  const [formState, { text }] = useFormState();\n\n  function setNameField() {\n    // manually setting the value of the \"name\" input\n    formState.setField('name', 'Mary Poppins');\n  }\n\n  return (\n    \u003c\u003e\n      \u003cinput {...text('name')} readOnly /\u003e\n      \u003cbutton onClick={setNameField}\u003eSet Name\u003c/button\u003e\n    \u003c/\u003e\n  );\n}\n```\n\nPlease note that when `formState.setField` is called, any existing errors that might have been set due to previous interactions from the user will be cleared, and both of the `validity` and the `touched` states of the input will be set to `true`.\n\nIt's also possible to clear a single input's value or to reset it to its initial value, if provided, using `formState.clearField` and `formState.resetField` respectively.\n\nAs a convenience you can also set the error value for a single input using `formState.setFieldError`.\n\n### Resetting The Form State\n\nThe form state can be cleared or reset back to its initial state if provided at any time using `formState.clear` and `formState.reset` respectively.\n\n```js\nfunction Form() {\n  const [formState, { text, email }] = useFormState({\n    email: 'hello@example.com',\n  });\n  return (\n    \u003c\u003e\n      \u003cinput {...text('first_name')} /\u003e\n      \u003cinput {...text('last_name')} /\u003e\n      \u003cinput {...email('email')} /\u003e\n      \u003cbutton onClick={formState.clear}\u003eClear All Fields\u003c/button\u003e\n      \u003cbutton onClick={formState.reset}\u003eReset to Initial State\u003c/button\u003e\n    \u003c/\u003e\n  );\n}\n```\n\n## Working with TypeScript\n\nWhen working with TypeScript, the compiler needs to know what values and inputs `useFormState` is expected to be working with.\n\nFor this reason, `useFormState` accepts an optional type argument that defines the state of the form and its fields which you could use to enforce type safety.\n\n```ts\ninterface LoginFormFields {\n  username: string;\n  password: string;\n  remember_me: boolean;\n}\n\nconst [formState, { text }] = useFormState\u003cLoginFormFields\u003e();\n                                          ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯\n// OK\n\u003cinput {...text('username')} /\u003e\nformState.values.username\n\n// Error\nformState.values.doesNotExist\n\u003cinput {...text('doesNotExist')} /\u003e\n```\n\nBy default, `useFormState` will use the type `any` for the form state and its inputs if no type argument is provided. Therefore, it is recommended that you provide one.\n\nBy default, the `errors` property will contain strings. If you return complex error objects from custom validation, you can provide an error type:\n\n```ts\ninterface I18nError {\n  en: string;\n  fr: string;\n}\n\ninterface LoginFormErrors {\n  username?: string | I18nError;\n  password?: string;\n}\n\nconst [formState, { text }] = useFormState\u003cLoginFormFields, LoginFormErrors\u003e();\n\nformState.errors.username; // Will be undefined, a string, or an I18nError.\n```\n\n## API\n\n```js\nimport { useFormState } from 'react-use-form-state';\n\nfunction FormComponent()\n  const [formState, inputs] = useFormState(initialState, formOptions);\n  return (\n    // ...\n  )\n}\n```\n\n### `initialState`\n\n`useFormState` takes an optional initial state object with keys as the name property of the form inputs, and values as the initial values of those inputs (similar to `defaultValue`/`defaultChecked`).\n\n### `formOptions`\n\n`useFormState` also accepts an optional form options object as a second argument with following properties:\n\n#### `formOptions.onBlur`\n\nA function that gets called upon any `blur` of the form's inputs. This functions provides access to the input's `blur` [`SyntheticEvent`](https://reactjs.org/docs/events.html)\n\n```js\nconst [formState, inputs] = useFormState(null, {\n  onBlur(e) {\n    // accessing the inputs target that triggered the blur event\n    const { name, value, ...target } = e.target;\n  },\n});\n```\n\n#### `formOptions.onChange`\n\nA function that gets triggered upon any `change` of the form's inputs, and before updating `formState`.\n\nThis function gives you access to the input's `change` [`SyntheticEvent`](https://reactjs.org/docs/events.html), the current `formState`, the next state after the change is applied.\n\n```js\nconst [formState, inputs] = useFormState(null, {\n  onChange(e, stateValues, nextStateValues) {\n    // accessing the actual inputs target that triggered the change event\n    const { name, value, ...target } = e.target;\n    // the state values prior to applying the change\n    formState.values === stateValues; // true\n    // the state values after applying the change\n    nextStateValues;\n    // the state value of the input. See Input Types below for more information.\n    nextStateValues[name];\n  },\n});\n```\n\n#### `formOptions.onTouched`\n\nA function that gets called after an input inside the form has lost focus, and is marked as touched. It will be called once throughout the component life cycle. This functions provides access to the input's `blur` [`SyntheticEvent`](https://reactjs.org/docs/events.html).\n\n```js\nconst [formState, inputs] = useFormState(null, {\n  onTouched(e) {\n    // accessing the inputs target that triggered the blur event\n    const { name, value, ...target } = e.target;\n  },\n});\n```\n\n#### `formOptions.onClear`\n\nA function that gets called after calling `formState.clear` indicating that all fields in the form state are cleared successfully.\n\n```js\nconst [formState, inputs] = useFormState(null, {\n  onClear() {\n    // form state was cleared successfully\n  },\n});\n\nformState.clear(); // clearing the form state\n```\n\n#### `formOptions.onReset`\n\nA function that gets called after calling `formState.reset` indicating that all fields in the form state are set to their initial values.\n\n```js\nconst [formState, inputs] = useFormState(null, {\n  onReset() {\n    // form state was reset successfully\n  },\n});\nformState.reset(); // resetting the form state\n```\n\n#### `formOptions.validateOnBlur`\n\nBy default, input validation is performed on both of the `change` and the `blur` events. Setting `validateOnBlur` to `true` will limit input validation to be **only** performed on `blur` (when the input loses focus). When set to `false`, input validation will **only** be performed on `change`.\n\n#### `formOptions.withIds`\n\nIndicates whether `useFormState` should generate and pass an `id` attribute to its fields. This is helpful when [working with labels](#labels-and-ids).\n\nIt can be one of the following:\n\nA `boolean` indicating whether [input types](#input-types) should pass an `id` attribute to the inputs (set to `false` by default).\n\n```js\nconst [formState, inputs] = useFormState(null, {\n  withIds: true,\n});\n```\n\nOr a custom id formatter: a function that gets called with the input's name and own value, and expected to return a unique string (using these parameters) that will be as the input id.\n\n```js\nconst [formState, inputs] = useFormState(null, {\n  withIds: (name, ownValue) =\u003e\n    ownValue ? `MyForm-${name}-${ownValue}` : `MyForm-${name}`,\n});\n```\n\nNote that when `withIds` is set to `false`, applying `input.label()` will be a no-op.\n\n### `[formState, inputs]`\n\nThe return value of `useFormState`. An array of two items, the first is the [form state](#form-state), and the second an [input types](#input-types) object.\n\n#### Form State\n\nThe first item returned by `useFormState`.\n\n```js\nconst [formState, inputs] = useFormState();\n```\n\nAn object containing the form state that updates during subsequent re-renders. It also include methods to update the form state manually.\n\n```ts\nformState = {\n  // an object holding the values of all input being rendered\n  values: {\n    [name: string]: string | string[] | boolean,\n  },\n\n  // an object indicating whether the value of each input is valid\n  validity: {\n    [name: string]?: boolean,\n  },\n\n  // an object holding all errors resulting from input validations\n  errors: {\n    [name: string]?: any,\n  },\n\n  // an object indicating whether the input was touched (focused) by the user\n  touched: {\n    [name: string]?: boolean,\n  },\n\n  // an object indicating whether the value of each input is pristine\n  pristine: {\n    [name: string]: boolean,\n  },\n\n  // whether the form is pristine or not\n  isPristine(): boolean,\n\n  // clears all fields in the form\n  clear(): void,\n\n  // clears the state of an input\n  clearField(name: string): void,\n\n  // resets all fields the form back to their initial state if provided\n  reset(): void,\n\n  // resets the state of an input back to its initial state if provided\n  resetField(name: string): void,\n\n  // updates the value of an input\n  setField(name: string, value: string): void,\n\n  // sets the error of an input\n  setFieldError(name: string, error: string): void,\n}\n```\n\n#### Input Types\n\nThe second item returned by `useFormState`.\n\n```js\nconst [formState, input] = useFormState();\n```\n\nAn object with keys as input types. Each type is a function that returns the appropriate props that can be spread on the corresponding input.\n\nThe following types are currently supported:\n\n| Type and Usage                                                  | State Shape                                                                |\n| --------------------------------------------------------------- | -------------------------------------------------------------------------- |\n| `\u003cinput {...input.email(name: string)} /\u003e`                      | `{ [name: string]: string }`                                               |\n| `\u003cinput {...input.color(name: string)} /\u003e`                      | `{ [name: string]: string }`                                               |\n| `\u003cinput {...input.password(name: string)} /\u003e`                   | `{ [name: string]: string }`                                               |\n| `\u003cinput {...input.text(name: string)} /\u003e`                       | `{ [name: string]: string }`                                               |\n| `\u003cinput {...input.url(name: string)} /\u003e`                        | `{ [name: string]: string }`                                               |\n| `\u003cinput {...input.search(name: string)} /\u003e`                     | `{ [name: string]: string }`                                               |\n| `\u003cinput {...input.number(name: string)} /\u003e`                     | `{ [name: string]: string }`                                               |\n| `\u003cinput {...input.range(name: string)} /\u003e`                      | `{ [name: string]: string }`                                               |\n| `\u003cinput {...input.tel(name: string)} /\u003e`                        | `{ [name: string]: string }`                                               |\n| `\u003cinput {...input.radio(name: string, ownValue: string)} /\u003e`    | `{ [name: string]: string }`                                               |\n| `\u003cinput {...input.checkbox(name: string, ownValue: string)} /\u003e` | `{ [name: string]: Array\u003cstring\u003e }`                                        |\n| `\u003cinput {...input.checkbox(name: string)} /\u003e`                   | `{ [name: string]: boolean }`                                              |\n| `\u003cinput {...input.date(name: string)} /\u003e`                       | `{ [name: string]: string }`                                               |\n| `\u003cinput {...input.month(name: string)} /\u003e`                      | `{ [name: string]: string }`                                               |\n| `\u003cinput {...input.week(name: string)} /\u003e`                       | `{ [name: string]: string }`                                               |\n| `\u003cinput {...input.time(name: string)} /\u003e`                       | `{ [name: string]: string }`                                               |\n| `\u003cselect {...input.select(name: string)} /\u003e`                    | `{ [name: string]: string }`                                               |\n| `\u003cselect {...input.selectMultiple(name: string)} /\u003e`            | `{ [name: string]: Array\u003cstring\u003e }`                                        |\n| `\u003ctextarea {...input.textarea(name: string)} /\u003e`                | `{ [name: string]: string }`                                               |\n| `\u003clabel {...input.label(name: string, value?: string)} /\u003e`      | N/A – `input.label()` is stateless and thus does not affect the form state |\n| `\u003cCustomControl {...input.raw(name: string)} /\u003e`                | `{ [name: string]: any }`                                                  |\n\n#### Input Options\n\nAlternatively, input type functions can be called with an object as the first argument. This object is used to [extend the functionality](#advanced-input-options) of the input. This includes attaching event handlers and performing input-level custom validation.\n\n```jsx\n\u003cinput\n  {...input.text({\n    name: 'username',\n    validate: value =\u003e validateUsername(value),\n    validateOnBlur: true,\n  })}\n/\u003e\n```\n\nThe following options can be passed:\n\n| key                                 | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |\n| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `name: string`                      | Required. The name of the input.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |\n| `value: string`                     | The input's own value. Only required by the `radio` input, and optional for the `checkbox` input.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |\n| `onChange(e): void`                 | Optional. A change event handler that's called with the input's `change` [`SyntheticEvent`](https://reactjs.org/docs/events.html).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |\n| `onBlur(e): void`                   | Optional. A blur event handler that's called with the input's `blur` [`SyntheticEvent`](https://reactjs.org/docs/events.html).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |\n| `validate(value, values, e): any`   | Optional (required for `raw` inputs). An input validation function that determines whether the input value is valid. It's called with the input value, all input values in the form, and the change/blur event (or the raw value of the control in the case of `.raw()`). The input is considered **valid** if this method returns `true` or `undefined`. Any [truthy value](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) other than `true` returned from this method will make the input **invalid**. Such values are used a **custom validation errors** that can be retrieved from [`state.errors`](#form-state). HTML5 validation rules are ignored when this function is specified. |\n| `compare(initialValue, value): any` | Optional (required for `raw` inputs). A comparison function that determines whether the input value is pristine. It's called with the input's initial value, and the input's current value. It must return a boolean indicating whether the form is pristine.                                                                                                                                                                                                                                                                                                                                                                                                                                         |\n| `validateOnBlur: boolean`           | Optional. Unspecified by default. When unspecified, input validation is performed on both of the `change` and the `blur` events. Setting `validateOnBlur` to `true` will limit input validation to be **only** performed on `blur` (when the input loses focus). When set to `false`, input validation will **only** be performed on `change`.                                                                                                                                                                                                                                                                                                                                                        |\n| `touchOnChange: boolean`            | Optional. `false` by default. When `false`, the input will be marked as touched when the `onBlur()` event handler is called. For custom controls that do not support `onBlur`, setting this to `true` will make it so inputs will be marked as touched when `onChange()` is called instead.                                                                                                                                                                                                                                                                                                                                                                                                           |\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwsmd%2Freact-use-form-state","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwsmd%2Freact-use-form-state","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwsmd%2Freact-use-form-state/lists"}