{"id":21927019,"url":"https://github.com/rzane/form","last_synced_at":"2026-04-12T10:32:30.686Z","repository":{"id":37095745,"uuid":"266869169","full_name":"rzane/form","owner":"rzane","description":"A type-safe approach to managing complex form state in React.","archived":false,"fork":false,"pushed_at":"2023-03-05T09:15:29.000Z","size":1883,"stargazers_count":1,"open_issues_count":44,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-08-08T22:49:44.577Z","etag":null,"topics":["form","hooks","react","react-native","type-safe","typescript","validate"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/rzane.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-25T20:00:22.000Z","updated_at":"2022-08-02T18:41:20.000Z","dependencies_parsed_at":"2024-11-29T02:00:10.467Z","dependency_job_id":null,"html_url":"https://github.com/rzane/form","commit_stats":{"total_commits":177,"total_committers":2,"mean_commits":88.5,"dds":0.05084745762711862,"last_synced_commit":"b5434b59f004d699821e9c8889312f14a59f5e52"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/rzane/form","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rzane%2Fform","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rzane%2Fform/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rzane%2Fform/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rzane%2Fform/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rzane","download_url":"https://codeload.github.com/rzane/form/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rzane%2Fform/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271745602,"owners_count":24813511,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-23T02:00:09.327Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["form","hooks","react","react-native","type-safe","typescript","validate"],"created_at":"2024-11-28T22:13:02.570Z","updated_at":"2025-12-30T21:39:19.197Z","avatar_url":"https://github.com/rzane.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e@stackup/form\u003c/h1\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n![Build](https://github.com/rzane/form/workflows/Build/badge.svg)\n![Version](https://img.shields.io/npm/v/@stackup/form)\n![Size](https://img.shields.io/bundlephobia/minzip/@stackup/form)\n![License](https://img.shields.io/npm/l/@stackup/form)\n\n\u003c/div\u003e\n\nA type-safe approach to managing complex form state in React.\n\nThis library provides integration with [@stackup/validate](https://github.com/rzane/validate) to handle validation. However, it should be pretty easy to integrate whatever validation library you prefer.\n\nYou should also checkout [@stackup/inputs](https://github.com/promptworks/inputs), which includes some ready-made form fields.\n\n## Usage\n\n```jsx\nimport React from \"react\";\nimport { useForm, useField } from \"@stackup/form\";\n\nconst Form = () =\u003e {\n  const form = useForm({ initialValue: { email: \"\", name: \"\" } });\n\n  const validate = useValidation(form, value =\u003e {\n    if (value.email) {\n      return { valid: true, value };\n    } else {\n      return { valid: false, error: { email: \"is required\" } };\n    }\n  });\n\n  const submit = useSubmit(validate, value =\u003e {\n    console.log(value);\n  });\n\n  return (\n    \u003cform onSubmit={submit}\u003e\n      \u003cInput type=\"email\" label=\"Email\" field={useField(form, \"email\")} /\u003e\n      \u003cInput type=\"text\" label=\"Name\" field={useField(form, \"name\")} /\u003e\n      \u003cbutton type=\"submit\"\u003eSave\u003c/button\u003e\n    \u003c/form\u003e\n  );\n};\n\nconst Input = ({\n  label,\n  field: { id, value, error, touched, setValue, setTouched },\n  ...props\n}) =\u003e (\n  \u003cdiv\u003e\n    \u003clabel htmlFor={id}\u003e{label}\u003c/label\u003e\n    \u003cinput\n      {...props}\n      id={id}\n      value={value}\n      onBlur={useCallback(() =\u003e setTouched(true), [])}\n      onChange={useCallback(e =\u003e setValue(e.target.value), [setValue])}\n    /\u003e\n    {touched \u0026\u0026 error \u0026\u0026 \u003cp\u003e{error}\u003c/p\u003e}\n  \u003c/div\u003e\n);\n```\n\n## API\n\n\u003c!-- Generated by documentation.js. Update this documentation by updating the source code. --\u003e\n\n#### Table of Contents\n\n- [useForm](#useform)\n- [useField](#usefield)\n- [useValidation](#usevalidation)\n- [useValidate](#usevalidate)\n- [useSubmit](#usesubmit)\n- [useReset](#usereset)\n- [useFieldItem](#usefielditem)\n- [usePushItem](#usepushitem)\n- [useInsertItem](#useinsertitem)\n- [useRemoveItem](#useremoveitem)\n- [useIdentifier](#useidentifier)\n- [Form](#form)\n- [FormField](#formfield)\n- [ValidateFn](#validatefn)\n- [Submit](#submit)\n- [Submission](#submission)\n- [Reset](#reset)\n- [UseFormOptions](#useformoptions)\n- [UseValidationOptions](#usevalidationoptions)\n\n### useForm\n\nCreate a new form. A form requires an initial value, a function to validate,\nand a submit handler.\n\nA form behaves just like any other field, but with some extra properties for\nmanaging submission.\n\nThe initial value for the form can be literally anything! Usually, it's an\nobject, but it could be any type of value.\n\n#### Parameters\n\n- `options` **[UseFormOptions](#useformoptions)\u0026lt;Value\u003e**\n\n#### Examples\n\nForm values can be primitive\n\n```javascript\nconst form = useForm({ initialValue: \"\" });\n```\n\nBut usually, they'll contain an object\n\n```javascript\nconst form = useForm({\n  initialValue: {\n    email: \"\",\n    name: \"\"\n  }\n});\n```\n\nReturns **[Form](#form)\u0026lt;Value\u003e**\n\n### useField\n\nCreate a field for a given property.\n\n#### Parameters\n\n- `field` **[FormField](#formfield)\u0026lt;Value\u003e**\n- `name` **[Name](https://developer.mozilla.org/)**\n\n#### Examples\n\n```javascript\nconst form = useForm({\n  initialValue: {\n    email: \"\",\n    profile: { name: \"\" } }\n  }\n});\n\nconst email = useField(form, \"email\");\nconst profile = useField(form, \"profile\");\nconst name = useField(profile, \"name\");\n```\n\nReturns **[FormField](#formfield)\u0026lt;any\u003e**\n\n### useValidation\n\nUse a plain ol' function for validation.\n\nThis hook can also be used to incorporate your favorite validation library.\n\n#### Parameters\n\n- `form` **[Form](#form)\u0026lt;Value, Value\u003e**\n- `fn` **[ValidateFn](#validatefn)\u0026lt;Value, Result\u003e**\n- `opts` **[UseValidationOptions](#usevalidationoptions)** (optional, default `{}`)\n\n#### Examples\n\n```javascript\nconst validation = useValidation(form, value =\u003e {\n  if (!value.email) {\n    return { valid: false, error: { email: \"can't be blank\" } };\n  }\n\n  return { valid: true, value };\n});\n```\n\nReturns **[Form](#form)\u0026lt;Value, Result\u003e**\n\n### useValidate\n\nAdd validation to the form using [@stackup/validate](https://github.com/rzane/validate).\n\n#### Parameters\n\n- `form` **[Form](#form)\u0026lt;Value, Value\u003e**\n- `validator` **Validator\u0026lt;(Value | any), Result\u003e**\n- `opts` **[UseValidationOptions](#usevalidationoptions)?**\n\n#### Examples\n\n```javascript\nconst validator = schema({\n  email: assert(isString).then(refute(isBlank))\n});\n\nconst validate = useValidate(form, validator);\n```\n\nReturns **[Form](#form)\u0026lt;Value, Result\u003e**\n\n### useSubmit\n\nCreate a submit handler for the form.\n\n#### Parameters\n\n- `form` **[Form](#form)\u0026lt;Value, Result\u003e**\n- `fn` **SubmitFn\u0026lt;Result\u003e**\n- `opts` **ValidateOptions** (optional, default `{touch:true}`)\n\n#### Examples\n\nSumbitting a form\n\n```javascript\nconst form = useForm({ initialValue: \"foo\" });\nconst submit = useSubmit(form, console.log);\n```\n\nSumbitting with validation\n\n```javascript\nconst form = useForm({ initialValue: \"foo\" });\nconst validate = useValidate(form, myValidator);\nconst submit = useSubmit(validate, console.log);\n```\n\nReturns **[Submit](#submit)**\n\n### useReset\n\nCreate a reset handler for the form.\n\n#### Parameters\n\n- `form` **[Form](#form)\u0026lt;Value, Result\u003e**\n\n#### Examples\n\n```javascript\nconst form = useForm({ initialValue: \"foo\" });\nconst reset = useReset(form);\n```\n\nReturns **[Reset](#reset)**\n\n### useFieldItem\n\nCreate a field for a specific index in an array.\n\nThis hook is intended for use in building forms with \"Add another\" functionality.\n\n#### Parameters\n\n- `field` **[FormField](#formfield)\u0026lt;[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)\u0026lt;Value\u003e\u003e**\n- `index` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)**\n\n#### Examples\n\n```javascript\nconst form = useForm({ initialValue: { pets: [{ name: \"\" }] } });\nconst pets = useField(form, \"pets\");\nconst pet = useFieldItem(pets, 0);\nconst name = useField(pet, \"name\");\n```\n\nReturns **[FormField](#formfield)\u0026lt;Value\u003e**\n\n### usePushItem\n\nAdds a new value to the end to an array of values.\n\nThis can be used to create a form with repeating fields.\n\n#### Parameters\n\n- `field` **[FormField](#formfield)\u0026lt;[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)\u0026lt;Value\u003e\u003e**\n- `value` **Value**\n\n#### Examples\n\n```javascript\nconst pets = useField(form, \"pets\");\nconst pet = useFieldItem(pets, 0);\nconst addPet = usePushItem(pets, { name: \"\" });\n```\n\n### useInsertItem\n\nAdds a new value at a specific position to an array of values.\n\nThis can be used to create a form with repeating fields.\n\n#### Parameters\n\n- `field` **[FormField](#formfield)\u0026lt;[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)\u0026lt;Value\u003e\u003e**\n- `index` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)**\n- `value` **Value**\n\n#### Examples\n\n```javascript\nconst pets = useField(form, \"pets\");\nconst pet = useFieldItem(pets, 0);\nconst insert = useInsertItem(pets, 0, { name: \"\" });\n```\n\n### useRemoveItem\n\nRemoves a value at the given index from array of values.\n\nThis can be used to create a form with repeating fields.\n\n#### Parameters\n\n- `field` **[FormField](#formfield)\u0026lt;[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)\u0026lt;Value\u003e\u003e**\n- `index` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)**\n\n#### Examples\n\n```javascript\nconst pets = useField(form, \"pets\");\nconst pet = useFieldItem(pets, 0);\nconst removePet = useRemoveItem(pets, 0);\n```\n\n### useIdentifier\n\nCreates a unique identifier that will remain consistent across re-renders.\n\nThis hook does not currently support SSR.\n\n#### Parameters\n\n- `id` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?**\n\nReturns **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**\n\n### Form\n\n**Extends FormField\u0026lt;Value\u003e**\n\nThe value returned by `useForm`.\n\n#### initialValue\n\nThe initial values for the form.\n\nType: Value\n\n#### initialError\n\nThe initial errors on the fields.\n\nType: FormError\u0026lt;Value\u003e\n\n#### initialTouched\n\nThe initially touched fields.\n\nType: FormTouched\u0026lt;Value\u003e\n\n#### setValidating\n\nIndicate that the form is validating\n\nType: SetState\u0026lt;[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)\u003e\n\n#### setSubmitting\n\nIndicate that the form is validating\n\nType: SetState\u0026lt;[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)\u003e\n\n#### setSubmission\n\nUpdate the form's submission status\n\nType: SetState\u0026lt;[Submission](#submission)\u003e\n\n#### reset\n\nReset the state of the form\n\nType: function (opts: ResetOptions\u0026lt;Value\u003e): void\n\n#### validate\n\nRun validation\n\nType: function (opts: ValidateOptions): [Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\u0026lt;ValidationResult\u0026lt;Value, Result\u003e\u003e\n\n### FormField\n\nThe primary form data structure.\n\n#### id\n\nA unique ID for this form field. This can be used to associate fields with a label.\n\nType: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)\n\n#### name\n\nThe name or array index that was given to [useField](#usefield) or [useFieldItem](#usefielditem).\n\nType: ([string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \\| [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number))\n\n#### value\n\nThe current value of the field.\n\nType: Value\n\n#### error\n\nAn error or errors that are associated with this field or it's children.\n\nType: FormError\u0026lt;Value\u003e\n\n#### touched\n\nIndicates that this field or it's children have been modified by the user.\n\nType: FormTouched\u0026lt;Value\u003e\n\n#### isValidating\n\nIndicates that validation is currently being run\n\nType: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)\n\n#### isSubmitting\n\nIndicates that the form is currently being submitted\n\nType: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)\n\n#### submission\n\nKeeps track of the form's submission status\n\nType: [Submission](#submission)\n\n#### setValue\n\nChange the value. Just like with `setState`, you can pass a callback\nto this function to get the current value and update it.\n\nType: SetState\u0026lt;Value\u003e\n\n#### setError\n\nUpdate the error.\n\nType: SetState\u0026lt;FormError\u0026lt;Value\u003e\u003e\n\n#### setTouched\n\nIndicate that this field has been touched. This is usually called in `onBlur`.\n\nType: SetState\u0026lt;FormTouched\u0026lt;Value\u003e\u003e\n\n### ValidateFn\n\nA function used for validation. This function must indicate whether\nor not the form is valid.\n\nThe `error` property can be used to set errors on the form.\n\nThe `value` property can be used to transform the form's values before\nvalidation.\n\nType: function (value: Value): (ValidationResult\u0026lt;Value, Result\u003e | PromiseLike\u0026lt;ValidationResult\u0026lt;Value, Result\u003e\u003e)\n\n### Submit\n\nSubmits the form.\n\nType: function (event: FormEvent\u0026lt;[HTMLFormElement](https://developer.mozilla.org/docs/Web/API/HTMLFormElement)\u003e): [Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\u0026lt;void\u003e\n\n### Submission\n\nKeeps track of submissions.\n\n#### count\n\nThe number of times the form has been submitted\n\nType: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)\n\n#### error\n\nIf the submission flow throws an error, it will appear here.\n\nType: [Error](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error)\n\n### Reset\n\nResets the form.\n\nType: function (event: FormEvent\u0026lt;[HTMLFormElement](https://developer.mozilla.org/docs/Web/API/HTMLFormElement)\u003e): [Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\u0026lt;void\u003e\n\n### UseFormOptions\n\nThe options that can be passed to [useForm](#useform).\n\n#### id\n\nCustomize the base ID for all fields.\n\nType: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)\n\n#### initialValue\n\nThe initial values for the form.\n\nType: Value\n\n#### initialError\n\nThe initial errors on the fields.\n\nType: FormError\u0026lt;Value\u003e\n\n#### initialTouched\n\nThe initially touched fields.\n\nType: FormTouched\u0026lt;Value\u003e\n\n### UseValidationOptions\n\nConfigures when validation runs.\n\n#### onChange\n\nEnables validation whenever values change.\n\nType: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)\n\n#### onBlur\n\nEnables validation whenever a field is touched.\n\nType: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frzane%2Fform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frzane%2Fform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frzane%2Fform/lists"}