{"id":4490,"url":"https://github.com/FaridSafi/react-native-gifted-form","last_synced_at":"2025-08-13T23:30:50.964Z","repository":{"id":54636086,"uuid":"45465455","full_name":"FaridSafi/react-native-gifted-form","owner":"FaridSafi","description":"📝 « One React-Native form component to rule them all »","archived":false,"fork":false,"pushed_at":"2020-08-17T02:05:49.000Z","size":1304,"stargazers_count":1443,"open_issues_count":80,"forks_count":214,"subscribers_count":33,"default_branch":"master","last_synced_at":"2024-10-29T20:56:27.482Z","etag":null,"topics":[],"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/FaridSafi.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":"2015-11-03T12:37:07.000Z","updated_at":"2024-10-16T20:20:20.000Z","dependencies_parsed_at":"2022-08-13T22:20:23.957Z","dependency_job_id":null,"html_url":"https://github.com/FaridSafi/react-native-gifted-form","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FaridSafi%2Freact-native-gifted-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FaridSafi%2Freact-native-gifted-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FaridSafi%2Freact-native-gifted-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FaridSafi%2Freact-native-gifted-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FaridSafi","download_url":"https://codeload.github.com/FaridSafi/react-native-gifted-form/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229786916,"owners_count":18123998,"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":[],"created_at":"2024-01-05T20:17:14.179Z","updated_at":"2024-12-15T05:30:29.302Z","avatar_url":"https://github.com/FaridSafi.png","language":"JavaScript","funding_links":[],"categories":["Components","JavaScript","组件","Libraries"],"sub_categories":["Forms","UI"],"readme":"# Gifted Form\n\n[![npm downloads](https://img.shields.io/npm/dm/react-native-gifted-form.svg)](https://www.npmjs.com/package/react-native-gifted-form)\n[![npm version](https://img.shields.io/npm/v/react-native-gifted-form.svg)](https://www.npmjs.com/package/react-native-gifted-form)\n[![Latest GitHub tag](https://img.shields.io/github/tag/FaridSafi/react-native-gifted-form.svg)](https://github.com/FaridSafi/react-native-gifted-form)\n\nForm component for React Native.\n\n![screenshot](https://raw.githubusercontent.com/FaridSafi/react-native-gifted-form/master/capture/signup.gif)\n\n### Example\n\n```js\nvar { GiftedForm, GiftedFormManager } = require('react-native-gifted-form');\n\nvar FormComponent = createReactClass({\n  render() {\n    return (\n      \u003cGiftedForm\n        formName='signupForm' // GiftedForm instances that use the same name will also share the same states\n        openModal={(route) =\u003e {\n          navigator.push(route); // The ModalWidget will be opened using this method. Tested with ExNavigator\n        }}\n        clearOnClose={false} // delete the values of the form when unmounted\n        defaults={{\n          /*\n          username: 'Farid',\n          'gender{M}': true,\n          password: 'abcdefg',\n          country: 'FR',\n          birthday: new Date(((new Date()).getFullYear() - 18)+''),\n          */\n        }}\n        validators={{\n          fullName: {\n            title: 'Full name',\n            validate: [{\n              validator: 'isLength',\n              arguments: [1, 23],\n              message: '{TITLE} must be between {ARGS[0]} and {ARGS[1]} characters'\n            }]\n          },\n          username: {\n            title: 'Username',\n            validate: [{\n              validator: 'isLength',\n              arguments: [3, 16],\n              message: '{TITLE} must be between {ARGS[0]} and {ARGS[1]} characters'\n            },{\n              validator: 'matches',\n              arguments: /^[a-zA-Z0-9]*$/,\n              message: '{TITLE} can contains only alphanumeric characters'\n            }]\n          },\n          password: {\n            title: 'Password',\n            validate: [{\n              validator: 'isLength',\n              arguments: [6, 16],\n              message: '{TITLE} must be between {ARGS[0]} and {ARGS[1]} characters'\n            }]\n          },\n          emailAddress: {\n            title: 'Email address',\n            validate: [{\n              validator: 'isLength',\n              arguments: [6, 255],\n            },{\n              validator: 'isEmail',\n            }]\n          },\n          bio: {\n            title: 'Biography',\n            validate: [{\n              validator: 'isLength',\n              arguments: [0, 512],\n              message: '{TITLE} must be between {ARGS[0]} and {ARGS[1]} characters'\n            }]\n          },\n          gender: {\n            title: 'Gender',\n            validate: [{\n              validator: (...args) =\u003e {\n                if (args[0] === undefined) {\n                  return false;\n                }\n                return true;\n              },\n              message: '{TITLE} is required',\n            }]\n          },\n          birthday: {\n            title: 'Birthday',\n            validate: [{\n              validator: 'isBefore',\n              arguments: [moment().utc().subtract(18, 'years').format('YYYY-MM-DD')],\n              message: 'You must be at least 18 years old'\n            }, {\n              validator: 'isAfter',\n              arguments: [moment().utc().subtract(100, 'years').format('YYYY-MM-DD')],\n              message: '{TITLE} is not valid'\n            }]\n          },\n          country: {\n            title: 'Country',\n            validate: [{\n              validator: 'isLength',\n              arguments: [2],\n              message: '{TITLE} is required'\n            }]\n          },\n        }}\n      \u003e\n        \u003cGiftedForm.SeparatorWidget /\u003e\n\n        \u003cGiftedForm.TextInputWidget\n          name='fullName' // mandatory\n          title='Full name'\n          image={require('../../assets/icons/color/user.png')}\n          placeholder='Marco Polo'\n          clearButtonMode='while-editing'\n        /\u003e\n\n        \u003cGiftedForm.TextInputWidget\n          name='username'\n          title='Username'\n          image={require('../../assets/icons/color/contact_card.png')}\n          placeholder='MarcoPolo'\n          clearButtonMode='while-editing'\n          onTextInputFocus={(currentText = '') =\u003e {\n            if (!currentText) {\n              let fullName = GiftedFormManager.getValue('signupForm', 'fullName');\n              if (fullName) {\n                return fullName.replace(/[^a-zA-Z0-9-_]/g, '');\n              }\n            }\n            return currentText;\n          }}\n        /\u003e\n\n        \u003cGiftedForm.TextInputWidget\n          name='password' // mandatory\n          title='Password'\n          placeholder='******'\n          clearButtonMode='while-editing'\n          secureTextEntry={true}\n          image={require('../../assets/icons/color/lock.png')}\n        /\u003e\n\n        \u003cGiftedForm.TextInputWidget\n          name='emailAddress' // mandatory\n          title='Email address'\n          placeholder='example@nomads.ly'\n          keyboardType='email-address'\n          clearButtonMode='while-editing'\n          image={require('../../assets/icons/color/email.png')}\n        /\u003e\n\n        \u003cGiftedForm.SeparatorWidget /\u003e\n\n        \u003cGiftedForm.ModalWidget\n          title='Gender'\n          displayValue='gender'\n          image={require('../../assets/icons/color/gender.png')}\n        \u003e\n          \u003cGiftedForm.SeparatorWidget /\u003e\n\n          \u003cGiftedForm.SelectWidget name='gender' title='Gender' multiple={false}\u003e\n            \u003cGiftedForm.OptionWidget image={require('../../assets/icons/color/female.png')} title='Female' value='F'/\u003e\n            \u003cGiftedForm.OptionWidget image={require('../../assets/icons/color/male.png')} title='Male' value='M'/\u003e\n          \u003c/GiftedForm.SelectWidget\u003e\n        \u003c/GiftedForm.ModalWidget\u003e\n\n        \u003cGiftedForm.ModalWidget\n          title='Birthday'\n          displayValue='birthday'\n          image={require('../../assets/icons/color/birthday.png')}\n          scrollEnabled={false}\n        \u003e\n          \u003cGiftedForm.SeparatorWidget/\u003e\n\n          \u003cGiftedForm.DatePickerIOSWidget\n            name='birthday'\n            mode='date'\n            getDefaultDate={() =\u003e {\n              return new Date(((new Date()).getFullYear() - 18)+'');\n            }}\n          /\u003e\n        \u003c/GiftedForm.ModalWidget\u003e\n\n        \u003cGiftedForm.ModalWidget\n          title='Country'\n          displayValue='country'\n          image={require('../../assets/icons/color/passport.png')}\n          scrollEnabled={false}\n        \u003e\n          \u003cGiftedForm.SelectCountryWidget\n            code='alpha2'\n            name='country'\n            title='Country'\n            autoFocus={true}\n          /\u003e\n        \u003c/GiftedForm.ModalWidget\u003e\n\n        \u003cGiftedForm.ModalWidget\n          title='Biography'\n          displayValue='bio'\n          image={require('../../assets/icons/color/book.png')}\n          scrollEnabled={true} // true by default\n        \u003e\n          \u003cGiftedForm.SeparatorWidget/\u003e\n\n          \u003cGiftedForm.TextAreaWidget\n            name='bio'\n            autoFocus={true}\n            placeholder='Something interesting about yourself'\n          /\u003e\n        \u003c/GiftedForm.ModalWidget\u003e\n\n        \u003cGiftedForm.ErrorsWidget/\u003e\n\n        \u003cGiftedForm.SubmitWidget\n          title='Sign up'\n          widgetStyles={{\n            submitButton: {\n              backgroundColor: themes.mainColor,\n            }\n          }}\n          onSubmit={(isValid, values, validationResults, postSubmit = null, modalNavigator = null) =\u003e {\n            if (isValid === true) {\n              // prepare object\n              values.gender = values.gender[0];\n              values.birthday = moment(values.birthday).format('YYYY-MM-DD');\n\n              /* Implement the request to your server using values variable\n              ** then you can do:\n              ** postSubmit(); // disable the loader\n              ** postSubmit(['An error occurred, please try again']); // disable the loader and display an error message\n              ** postSubmit(['Username already taken', 'Email already taken']); // disable the loader and display an error message\n              ** GiftedFormManager.reset('signupForm'); // clear the states of the form manually. 'signupForm' is the formName used\n              */\n            }\n          }}\n        /\u003e\n\n        \u003cGiftedForm.NoticeWidget\n          title='By signing up, you agree to the Terms of Service and Privacy Policity.'\n        /\u003e\n\n        \u003cGiftedForm.HiddenWidget name='tos' value={true} /\u003e\n      \u003c/GiftedForm\u003e\n    );\n  }\n});\n```\n\n### Storing form's state elsewhere (could be used with Redux) - Beta feature\n\nPass `value` prop to your widgets and `onValueChange` to your GiftedForm to store your state outside of GiftedFormManager's store.\n\nIMPORTANT: currently only TextInputWidget and HiddenWidget support this feature. PR's are welcome for the other widgets ;)\n\n```js\nimport React, { AppRegistry, Component } from 'react-native'\nimport { GiftedForm, GiftedFormManager } from 'react-native-gifted-form'\n\nclass Form extends Component {\n  constructor(props, context) {\n    super(props, context)\n    this.state = {\n      form: {\n        fullName: 'Marco Polo',\n        tos: false,\n      }\n    }\n  }\n\n  handleValueChange(values) {\n    console.log('handleValueChange', values)\n    this.setState({ form: values })\n  }\n\n  render() {\n    const { fullName, tos, gender } = this.state.form\n    console.log('render', this.state.form)\n    return (\n      \u003cGiftedForm\n        formName='signupForm'\n        openModal={(route) =\u003e { this.props.navigator.push(route) }}\n        onValueChange={this.handleValueChange.bind(this)}\n      \u003e\n        \u003cGiftedForm.TextInputWidget\n          name='fullName'\n          title='Full name'\n          placeholder='Marco Polo'\n          clearButtonMode='while-editing'\n          value={fullName}\n        /\u003e\n        \u003cGiftedForm.HiddenWidget name='tos' value={tos} /\u003e\n      \u003c/GiftedForm\u003e\n    )\n  }\n}\n\nAppRegistry.registerComponent('Form', () =\u003e Form)\n```\n\n### Installation\n\n```console\nnpm install react-native-gifted-form --save\n# OR\nyarn add react-native-gifted-form\n```\n\n### Available widgets\n\n- TextInputWidget - A text input\n- TextAreaWidget - A text area\n- GooglePlacesWidget - A Google Places picker based on react-native-google-places-autocomplete\n- ModalWidget - A route opener for nested forms\n- GroupWidget - A widgets container with a title\n- HiddenWidget - A non-displayed widget. The value will be passed to SubmitWidget\n- LoadingWidget - A loader\n- RowWidget - A touchable row with title/image\n- RowValueWidget - A touchable row with title/image and a value\n- SelectCountryWidget - A country picker. Flags made by www.IconDrawer.com\n- SelectWidget - A select menu\n- SeparatorWidget - A 10px widgets separator\n- SubmitWidget - A submit button that trigger form validators and error displaying\n- SwitchWidget - A switch\n- DatePickerIOSWidget - Date picker for iOS\n- NoticeWidget - A notice information - PR wanted for onPress handler\n\nSee the [widget sources](https://github.com/FaridSafi/react-native-gifted-form/tree/master/widgets) for full props details.\n\n### Custom widgets\n\nWidgets must implement the mixin `GiftedForm.WidgetMixin`. See [TextAreaWidget](https://github.com/FaridSafi/react-native-gifted-form/blob/master/widgets/TextAreaWidget.js) for a good example.\n\n### Contributing\n\nPull requests are welcome! The author is very busy at the moment but there are also some contributors who are also helping out.\n\n### License\n\n[MIT](LICENSE)\n\nFeel free to ask me questions on Twitter [@FaridSafi](https://www.twitter.com/FaridSafi)!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFaridSafi%2Freact-native-gifted-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FFaridSafi%2Freact-native-gifted-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFaridSafi%2Freact-native-gifted-form/lists"}