View on GitHub


Test Coverage
[![Build Status](](
[![Test Coverage](](

# RSFormView

## What is it?

RSFormView is a library that helps you build fully customizable forms for data entry in a few minutes.

<img src="" height="440">

## Installation

RSFormView is available through [CocoaPods]( To install it, simply add the following line to your Podfile:

pod 'RSFormView', '~> 2.1.1' 
## Usage

1. Add a FormView to your view controller, you can do this either programatically or via Storyboards.

let formView = FormView(frame: frame)
Add a `UIView` to your view controller and change the class name to `FormView` and the module to `RSFormView`.

2. Set your view controller as FormViewDelegate:
import RSFormView

class YourViewController: UIViewController, FormViewDelegate { ... }
and implement
func didUpdateFields(in formView: FormView, allFieldsValid: Bool)
This function will be called any time a user enters any data in the form, so it's a great place to update other views dependent on the entered data.

3. Set your view controller as the FormView delegate
formView.delegate = self

4. Set a FormViewModel to your formView

A `FormViewModel` can be any class that implements the `FormViewModel` delegate.
For a class to implement `FormViewModel` delegate  you only need to define an array of `FormItem`.
Each `FormItem` will determine the behavior and validation of each text field in your form.
Out of the box, RSFormView provides the following subclasses of `FormItem`:
- `TextCellItem`: A single label, or a "section header"
- `TextFieldCellItem`: A single text field.
- `TwoTextFieldCellItem`: Two text fields.

You can add your own custom `FormItem`s, check the `Custom Items` section for more information.

## FieldType

`fieldType` is a FormField property that determines the behaviour of the represented TextField.

 - email: Will present the email keyboard when the field is selected and validate that the text entry is in an email format
 - date: Will present a native date picker when the field is selected and validate that the entry is not empty
 - integer: Will present the numeric keyboard when the field is selected and validate that the text entry can be casted to Int
 - double: Will present the decimal keyboard when the field is selected and validate that the text entry can be casted to Double, pass the max decimal places as a parameter of this enum case
 - password: Will mask the text entry in UI and validate that the text entry is not empty
 - usPhone: Will decorate the text entry with slashes (111-111-1111) and validate that the text entry is in a valid US phone number format

 Check `FieldType` definition for more supported cases.

 ## ValidationType

 `validationType` is a `FormField` property that determines the validation behaviour of the represented TextField.
 Different `FieldType`s provide different default validations but the validation can be overriden by setting a `ValidationType` to the `FormField`.

 - nonEmpty: Will mark the field invalid if the text entry is empty
 - none: No validation will be made, the field will never be marked invalid unless manually made so
 - integer: Will mark the field invalid if the text entry is not an integer
 - double: Will mark the field invalid if the text entry is not a double, max 2 decimal places
 - usState: Will validate that the text entry matches the name or abbreviation of any of the US states
 - custom: Pass this case a block with your custom validation.

Custom example:
yourFormField.validationType = .custom(evaluator: { [weak self] updatedValue in
  let otherFormField = self?.fields().first { $ == "OtherFormFieldName" }
  let otherFormFieldValue = otherFormField?.value ?? ""
  return updatedValue.count > 5 && updatedValue == otherFormFieldValue
//In this example the field will be marked valid if the text entry has mora characters than 5 and its text entry is the same as the field with identifier "OtherTextFieldName"

## FormItem

A `FormItem` defines the basic behaviour of a row which is then specialized by subclassing it. You should never use instances of FormItem directly, RSFormView provides the following subclasses of FormItem out of the box:

TextCellItem: A single label, or a "section header"
TextFieldCellItem: A single text field.
TwoTextFieldCellItem: Two text fields.

1. One Text Field item:

let birthdateField = FormField(name: "Birthdate field", // the identifier of the field, use this to collect the data later
                               initialValue: "", // the inital value of the field, if its in a date formate it will auto select that date in the picker
                               placeholder: FieldName.birthdate.rawValue, // The placeholder when there's no value and text field title when there is
                               fieldType: .date, //The Type of the field, .date will present a native picker view when tapping on the text field
                               isValid: false, //The initial validation state. The field won't be marked invalid until data is entered or removed
                               errorMessage: "Please enter a birthdate") //The error message to be displayed when the entry is invalid or empty

let formItem = TextFieldCellItem(with: birthdateField)

2. Two Text Field item:

let firstFormField = FormField(...)
let secondFormField = FormField(...)

let formItem = TwoTextFieldCellItem(firstField: firstFormField, secondField: secondFormField)

3. Text Cell Item (may be used as a section header or text hint):
let attributedString = NSAttributedString(...)
let formItem = TextCellItem()
formItem.attributedString = attributedString

As an easy way to test the pod, we provide a the class BasaicFormViewModel. It receives a list of items and will show the form without additional customization. 

//  birthdateField defined above
formView.viewModel = BasicFormViewModel(items: [TextFieldCellItem(with: birthdateField)])

You can see this approach in the VanillaExample folder on this repository. 

1. Configure your form looks

Create a `FormConfigurator` change any colors or fonts you need and set it to your form view.
let configurator = FormConfigurator()
configurator.textColor = UIColor.lightGray
configurator.validTitleColor =
configurator.titleFont = UIFont.systemFont(withSize: 13)
formView.formConfigurator = configurator

Use the UIColor extension `formColor(red: Int, green: Int, blue: Int)`  to create new UIColors.
let configurator = FormConfigurator()
let darkPurple = UIColor.formColor(red: 140, green: 20, blue: 252)
configurator.editingTitleColor = darkPurple
formView.formConfigurator = configurator

Choose whether to hide the bottom line by setting the bottom line colors to clear (they are set colored by default)
let configurator = FormConfigurator()
configurator.validLineColor = UIColor.clear
configurator.invalidLineColor = UIColor.clear
configurator.editingLineColor = UIColor.clear
formView.formConfigurator = configurator

Choose whether to show borders by setting the border colors to the value desired (they are set clear by default).
Also set the border width and corner radius as desired.
let configurator = FormConfigurator()
configurator.validBorderColor = UIColor.gray
configurator.invalidBorderColor =
configurator.editingBorderColor = UIColor.darkPurple
configurator.borderCornerRadius = 20
configurator.borderWidth = 2
formView.formConfigurator = configurator

<img src="" height="440">

Disable tableView scrolling, which is enabled by default.
let configurator = FormConfigurator()
configurator.isScrollEnabled = false
formView.formConfigurator = configurator

6. Collect data

Any text entry made in your form will be collected in your `FormViewModel`  `items`.
Since you may have more than one text field per item a better way for collecting your data is making use of the `fields()` function of the `FormViewModel`, like this:
var user = User()
formViewModel.fields().forEach {
  switch $ {
  case "First Name":
    user.firstName = $0.value
  case "Birthdate":
    user.birthdate = $0.value
    print("\($ \($0.value)")

## Custom Form Items
If you need custom fields and the customization possibilities of the `FormConfigurator` are not enough, you can implement your own Fields.
To do so, follow these steps:
1- Create your custom `UITableViewCell` as you would normally do for any tableView.
2- Instead of subclassing from `UITableViewCell`, use `FormTableViewCell` as a base class.
3- Override `update` and `updateErrorState` to implement your own UI updates for the field.
4- Create a subclass of `FormItem` that overrides `cellIdentifier` and returns a valid reuseID.
5- In your formViewModel implementation, override the `customCellSetup` callback and register your new cell on the tableView.

If you need an example, you can check the `StepperCell` and `StepperCellItem` classes on the Example project.

## Server Side Validation

To manually mark fields invalid (for example after a server side validation) you can simply do:

``` swift
yourFormView.markItemInvalid(fieldName: "EmailFieldName", errorMessage: "Oops, This email is already taken")

After the user makes any edit in the invalid field it will no longer be marked invalid unless the real time validation doesn't pass.

## Example App

Clone this repo and run the example app to take a look at some of the RSFormView functionalities

## Contribute

To contribute to this library: fork this repository and create a Pull Request from your fork, detailing what are you improving/extending, the approach taken and screenshots to proof functionality added.

You can also open issues in this repository and our team will tackle them as soon as possible.

## License

RSFormView is available under the MIT license. See the LICENSE file for more info.

## Credits

**RSFormView** is authored and mantained by [Rootstrap]( and [German Stabile]( with the help of our [contributors](

[<img src="" width="100"/>](