DEV Community


Easy field masking in Swift

Daniel Cardona Rojas
iOS & Flutter Developer
・2 min read

When working with forms its is very likely that you will need to do field masking.

In this short article I want to present a small and flexible library called Veil that allows us to do this very easily.

Veil is a pure swift library that is available through Swift Package Manager, it does not depend on UIKit and instead
is a pure string processing utility, so use on any platform with UIKit or SwiftUI.

If you're a iOS developer its very likely that you might have stumbled with this problem and might have tried solving this by implementing UITextFieldDelegate
shouldReplaceCharacters:in range method. This is usually a painful experience as dealing with ranges is all around not that comfortable.

Veil offers a very simple solution to masking which does not require the developer to implement UITextFieldDelegate, instead can be easily
used with target action pattern.


Referring the documentation of the official repository, we can see a common example of formatting date input
into mm/yy

let dateMask = Veil(pattern: "## / ##")
let result = dateMask.mask(input: "234")
// result = "23 / 4"
Enter fullscreen mode Exit fullscreen mode

So first we need to supply some masking pattern, Veil uses a default configuration (which can be replaced)
where # represent digits while * any character. Anything else within the pattern will be
inserted automatically into the resulting string, so typing "234" will yield "23 / 4" (including spaces).

Usage with UITextField

let dateMask = Veil(pattern: "## / ##")

@objc func textDidChange(_ sender: UITextField) {
    guard let currentText = sender.text else  {

    sender.text = dateMask.mask(input: currentText, exhaustive: false)
Enter fullscreen mode Exit fullscreen mode

How it works

Internally Veil parses the pattern string into an array of tokens where a Token is

enum Token {
    case digit, any
    case symbol(Character)
Enter fullscreen mode Exit fullscreen mode

So a pattern like "## / ##" will result in the array of tokens:

[.digit, .digit, .symbol(" "), .symbol("/"), .symbol(" "), .digit, .digit]
Enter fullscreen mode Exit fullscreen mode

It will walk through input string matching against the token pattern until either is exhausted.
This also implies you get automatic input blocking.

I encourage everyone to give this a try, and let me know you're thoughts.


Discussion (0)