{"id":2544,"url":"https://github.com/hyperoslo/Form","last_synced_at":"2025-08-03T00:31:58.249Z","repository":{"id":56911592,"uuid":"145678527","full_name":"hyperoslo/Form","owner":"hyperoslo","description":"The most flexible and powerful way to build a form on iOS","archived":false,"fork":true,"pushed_at":"2018-08-22T08:19:10.000Z","size":8091,"stargazers_count":37,"open_issues_count":0,"forks_count":9,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-11-24T16:48:59.847Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://hyper.no","language":"Objective-C","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"3lvis/Form","license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hyperoslo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2018-08-22T08:20:08.000Z","updated_at":"2024-06-07T09:13:24.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hyperoslo/Form","commit_stats":null,"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperoslo%2FForm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperoslo%2FForm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperoslo%2FForm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperoslo%2FForm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hyperoslo","download_url":"https://codeload.github.com/hyperoslo/Form/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228510723,"owners_count":17931757,"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:16:16.438Z","updated_at":"2024-12-06T18:30:33.875Z","avatar_url":"https://github.com/hyperoslo.png","language":"Objective-C","funding_links":[],"categories":["UI"],"sub_categories":["Form \u0026 Settings","Other free courses"],"readme":"![Form logo](https://raw.githubusercontent.com/3lvis/Form/master/Images/logo-v6.png)\n\n[![Version](https://img.shields.io/cocoapods/v/Form.svg?style=flat)](http://cocoadocs.org/docsets/Form)\n[![License](https://img.shields.io/cocoapods/l/Form.svg?style=flat)](http://cocoadocs.org/docsets/Form)\n[![Platform](https://img.shields.io/cocoapods/p/Form.svg?style=flat)](http://cocoadocs.org/docsets/Form)\n[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/3lvis/Form)\n\nThe most flexible and powerful way to build a form on iOS.\n\nForm came out from our need to have a form that could share logic between our iOS apps and our web clients. We found that JSON was the best way to achieve this.\n\nForm includes the following features:\n\n- Multiple groups: For example, you can have a group for personal details and another one for shipping information\n- [Field validations](https://github.com/3lvis/Form/blob/d426e7b090fee7a630d1208b87c63a85b6aaf5df/Demos/Basic-ObjC/Basic-ObjC/Assets/forms.json#L19): We support `required`, `max_length`, `min_length`, `min_value`, `max_value` and `format` (regex). We also support many field types, like `text`, `number`, `phone_number`, `email`, `date`, `name`, `count`, `segment`, `switch`, and more\n- [Custom sizes](https://github.com/3lvis/Form/blob/d426e7b090fee7a630d1208b87c63a85b6aaf5df/Demos/Basic-ObjC/Basic-ObjC/Assets/forms.json#L15): Total `width` is handled as 100% while `height` is handled in chunks of [85 px](https://github.com/3lvis/Form/blob/b1a542d042a45a9a3056fb8969b5704e51fda1f4/Source/Cells/Base/FORMBaseFieldCell.h#L15)\n- [Custom fields](https://github.com/3lvis/Form/blob/d426e7b090fee7a630d1208b87c63a85b6aaf5df/Demos/Basic-ObjC/Basic-ObjC/Assets/forms.json#L78): You can register your custom fields, and it's pretty simple (our basic example includes how to make an `image` field)\n- [Formulas or computed values](https://github.com/3lvis/Form/blob/d426e7b090fee7a630d1208b87c63a85b6aaf5df/Demos/Basic-ObjC/Basic-ObjC/Assets/forms.json#L47): We support fields that contain generated values from other fields\n- [Targets](https://github.com/3lvis/Form/blob/d426e7b090fee7a630d1208b87c63a85b6aaf5df/Demos/Basic-ObjC/Basic-ObjC/Assets/forms.json#L127): `hide`, `show`, `update`, `enable`, `disable` or `clear` a field using a target. It's pretty powerful, and you can even set a condition for your target to run\n- [Dropdowns](https://github.com/3lvis/Form/blob/d426e7b090fee7a630d1208b87c63a85b6aaf5df/Demos/Basic-ObjC/Basic-ObjC/Assets/forms.json#L122): Generating dropdowns is as easy as adding values to your field, values support `default` flags, targets (in case you want to trigger hiding a field based on a selection), string and numeric values or showing additional info (in case you want to hint the consequences of your selection).\n\nForm works both on the iPhone and the iPad.\n\nYou can try one of our demos by running this command in your Terminal:\n\n```ruby\npod try Form\n```\n\n## Usage\n\n### Basic Form\n\nThis are the required steps to create a basic form with a first name field.\n\n![Form](https://github.com/3lvis/Form/blob/master/Images/basic-form.png)\n\n#### JSON\n```json\n[\n  {\n    \"id\":\"group-id\",\n    \"title\":\"Group title\",\n    \"sections\":[\n      {\n        \"id\":\"section-0\",\n        \"fields\":[\n          {\n            \"id\":\"first_name\",\n            \"title\":\"First name\",\n            \"type\":\"name\",\n            \"size\":{\n              \"width\":30,\n              \"height\":1\n            }\n          }\n        ]\n      }\n    ]\n  }\n]\n```\n\n\n#### In your iOS app\n\n**AppDelegate**\n\n```objc\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n    // Don't forget to set your style, or use the default one if you want\n    [FORMDefaultStyle applyStyle];\n\n    //...\n}\n```\n\n**Subclass**\n\nMake sure that your `UICollectionViewController` is a subclass of `FORMViewController`.\n\n---------------------------\n\n### Targets\n\nTargets are one of the most powerful features of form, and we support to `hide`, `show`, `update`, `enable`, `disable` or `clear` a field using a target. You can even set a condition for your target to run!\n\nIn the following example we show how to hide or show a field based on a dropdown selection.\n\n![Targets](https://github.com/3lvis/Form/blob/master/Images/target.gif)\n\n#### JSON\n\n```json\n[\n  {\n    \"id\":\"group-id\",\n    \"title\":\"Group title\",\n    \"sections\":[\n      {\n        \"id\":\"section-0\",\n        \"fields\":[\n          {\n            \"id\":\"employment_type\",\n            \"title\":\"Employment type\",\n            \"type\":\"select\",\n            \"size\":{\n              \"width\":30,\n              \"height\":1\n            },\n            \"values\":[\n              {\n                \"id\":0,\n                \"title\":\"Part time\",\n                \"default\":true,\n                \"targets\":[\n                  {\n                    \"id\":\"bonus\",\n                    \"type\":\"field\",\n                    \"action\":\"hide\"\n                  }\n                ]\n              },\n              {\n                \"id\":1,\n                \"title\":\"Full time\",\n                \"targets\":[\n                  {\n                    \"id\":\"bonus\",\n                    \"type\":\"field\",\n                    \"action\":\"show\"\n                  }\n                ]\n              }\n            ]\n          },\n          {\n            \"id\":\"bonus\",\n            \"title\":\"Bonus\",\n            \"type\":\"number\",\n            \"size\":{\n              \"width\":30,\n              \"height\":1\n            }\n          }\n        ]\n      }\n    ]\n  }\n]\n```\n\n### Group Collapsibility\n\nGroups have two JSON based collapsibility options: `collapsed` and `collapsible`\n\nThe `collapsed` option accepts `true` or `false` and defines the default state for the group it is added to. The default is `false`.\n\nThe `collapsible` option also accepts `true` or `false` but defines whether or not a group can be collapsed at all. Defining this option as `false`, prevents a group from being collapsed on click or with `collapseAllGroupsForCollectionView`. The default is `true`.\n\nIn your application code, you can also call `collapseAllGroupsForCollectionView` on the data source to collapse all groups in a collection view.\n\n### Counter Fields\n\nTo make quick and easy integer adjustments without popping up a keyboard, you can use the  `count` field. It works just like a `number` field but provides a minus button in the UITextField's leftView and a plus button in the rightView. A tap on either will decrease or increase, respectively, the number by a value of one.\n\n#### Example JSON\n```json\n{\n  \"groups\":[\n    {\n      \"id\":\"counter\",\n      \"title\":\"Counter Example\",\n      \"sections\":[\n        {\n          \"id\":\"counter-example\",\n          \"fields\":[\n            {\n              \"id\":\"guests\",\n              \"title\":\"Present Guests\",\n              \"info\":\"Press minus to decrease, plus to increase\",\n              \"type\":\"count\",\n              \"value\":0,\n              \"size\":{\n                \"width\":25,\n                \"height\":1\n              },\n              \"validations\":{\n                \"required\":true,\n                \"min_value\":0,\n                \"max_value\":100\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n### Segment Fields\n\nSegment fields can be used in place of text or select fields where the options are known and limited. Since segment fields do not require multiple taps or keyboard entry, data can be recorded quickly and easily with a single click. The `segment` field type allows for multiple values like the `select` field type and supports many of the same attributes.\n\n#### Example JSON\n```json\n{\n  \"groups\":[\n    {\n      \"id\":\"group1\",\n      \"title\":\"Segment Example\",\n      \"sections\":[\n        {\n          \"id\":\"section1\",\n          \"fields\":[\n            {\n              \"id\":\"location\",\n              \"title\":\"Work Location\",\n              \"type\":\"segment\",\n              \"styles\":{\n                \"font\":\"AvenirNext-DemiBold\",\n                \"font_size\":\"16.0\",\n                \"tint_color\":\"#CBEDBF\"\n              },\n              \"values\":[\n                {\n                  \"id\":\"in_house\",\n                  \"title\":\"In-house\",\n                  \"info\":\"In-house employee\",\n                  \"default\":true,\n                },\n                {\n                  \"id\":\"remote\",\n                  \"title\":\"Remote\",\n                }\n              ],\n              \"size\":{\n                \"width\":50,\n                \"height\":1\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n### Switch Fields\n\nSwitch fields can be used where a true or false response is desired. The `switch` field type allows for a single value of `0`, `false`, `1`, or `true`. Background and tint color styles are also available for this field.\n\n#### Example JSON\n```json\n{\n  \"groups\":[\n    {\n      \"id\":\"group1\",\n      \"title\":\"Switch Example\",\n      \"sections\":[\n        {\n          \"id\":\"section1\",\n          \"fields\":[\n            {\n              \"id\":\"budget_approved\",\n              \"title\":\"Budget Approved\",\n              \"type\":\"switch\",\n              \"styles\":{\n                \"tint_color\":\"#CBEDBF\"\n              },\n              \"value\":false,\n              \"size\":{\n                \"width\":50,\n                \"height\":1\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n### Accessibility Labels\n\nAccessibility labels are used by VoiceOver on iOS to provide feedback to users with visual impairments. According to Apple, the accessibility label attribute is \"a short, localized word or phrase that succinctly describes the control or view, but does not identify the element's type. Examples are 'Add' or 'Play.'\"\n\nField values are automatically mapped to Accessibility Value attributes to provide accurate feedback to users.\n\nIn addition to providing assistive feedback to users with impairments, accessibility labels can be useful for UI testing. Libraries such as [KIF](https://github.com/kif-framework/KIF), [EarlGrey](https://github.com/google/EarlGrey), and [Calabash](http://calaba.sh/) can use accessibility labels to access and control fields.\n\n#### Example JSON\n```json\n{\n  \"groups\":[\n    {\n      \"id\":\"group1\",\n      \"title\":\"Accessibility Example\",\n      \"sections\":[\n        {\n          \"id\":\"section1\",\n          \"fields\":[\n            {\n              \"id\":\"first_name\",\n              \"title\":\"First Name\",\n              \"info\":\"Enter your first name\",\n              \"accessibility_label\":\"First Name Accessibility Label\",\n              \"type\":\"name\",\n              \"size\":{\n                \"width\":25,\n                \"height\":1\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\n## FAQ\n\n### How do I get the contents of a field?\n\n```objc\nFORMField *targetField = [dataSource fieldWithID:@\"display_name\" includingHiddenFields:YES];\nid value = targetField.value;\n// Do something with value\n```\n\n### How do I get all the values of the Form?\n\n```objc\nNSDictionary *initialValues = @{@\"email\" : @\"hi@there.com\",\n                                @\"companies[0].name\" : @\"Facebook\",\n                                @\"companies[0].phone_number\" : @\"1222333\"};\n\nFORMDataSource *dataSource = [[FORMDataSource alloc] initWithJSON:JSON\n                                                   collectionView:nil\n                                                           layout:nil\n                                                           values:initialValues\n                                                         disabled:NO];\nNSDictionary *values = dataSource.values;\n// Do something with values\n```\n\n### How do I make a universal Form?\n\nYou have to specify and iPhone specific JSON file. Something [like this](https://github.com/3lvis/Form/blob/master/iPhone-Storyboard/Form.json), check the iPhone-Storyboard demo for more information.\n\nWe went for this approach since it gives the developers more control over the UI. You have to add a check for device and present the JSON file that matches the device.\n\n### How do I dynamically update a field's values?\n\nThe method below takes two arguments: `fieldID` and `options`. The `fieldID` argument is simply an NSString with the ID of the field to update. The `options` argument is an NSArray of NSDictionaries with `valueID`, `valueName`, and `defaultValue` keys. A similar approach could be used to take data from another method or web-service and update your field with it. This approach can be used with `select` and `segment` fields.\n\n```objc\n- (void)updateSelectField:(NSString *)fieldID withOptions:(NSArray *)options {\n    __weak typeof(self)weakSelf = self;\n\n    [self.dataSource fieldWithID:fieldID includingHiddenFields:YES completion:^(FORMField *field, NSIndexPath *indexPath) {\n        NSMutableArray *values = @[].mutableCopy;\n\n        for (NSDictionary *option in options) {\n            FORMFieldValue *fieldValue = [FORMFieldValue new];\n            fieldValue.valueID = [option valueForKey:@\"valueID\"];\n            fieldValue.title = [option valueForKey:@\"valueName\"];\n            fieldValue.default = [option valueForKey:@\"defaultValue\"];\n            fieldValue.field = field;\n\n            [values addObject:fieldValue];\n        }\n\n        field.values = [values copy];\n\n        if (!field.hidden) {\n          [weakSelf.dataSource reloadFieldsAtIndexPaths:@[indexPath]];\n        }\n    }];\n}\n```\n\n## Installation\n\n**Form** is available through [CocoaPods](http://cocoapods.org). To install it, simply add the following line to your Podfile:\n\n```ruby\nuse_frameworks!\n\npod 'Form'\n```\n\n## Contributing\n\nPlease check our [playbook](https://github.com/3lvis/playbook/blob/master/GIT_AND_GITHUB.md) for guidelines on contributing.\n\nDetailed discussions regarding code might be easier to have in the [Form channel on Gitter](https://gitter.im/3lvis/Form).\n\n## Credits\n\n[Hyper](http://hyper.no) made this. We’re a digital communications agency with a passion for good code and delightful user experiences. If you’re using this library we probably want to [hire you](https://github.com/3lvis/iOS-playbook/blob/master/HYPER_RECIPES.md) (we consider remote employees too, the only requirement is that you’re awesome).\n\n## License\n\nForm is available under the MIT license. See the [LICENSE](https://github.com/3lvis/Form/blob/master/LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyperoslo%2FForm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhyperoslo%2FForm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyperoslo%2FForm/lists"}