Search code examples
swiftuiswiftui-form

How to create TextField that only accepts numbers


I'm new to SwiftUI and iOS, and I'm trying to create an input field that will only accept numbers.

 TextField("Total number of people", text: $numOfPeople)

The TextField currently allows alphabetic characters, how do I make it so that the user can only input numbers?


Solution

  • There are several different initialisers that you can use for TextField that take a formatter/format and allow you to use a binding that is not a String. This allows you to ensure that only number values can be entered.

    For iOS 13+ we can use the following initialiser:

    init<S, V>(S, value: Binding<V>, formatter: Formatter)

    struct TextFieldExample: View {
        @State private var number: Double? // Make this optional to allow an empty TextField
        var body: some View {
            TextField("Placeholder", value: $number, formatter: NumberFormatter())
        }
    }
    

    Or for iOS 15+ you can use the following

    init<S, F>(S, value: Binding<F.FormatInput>, format: F, prompt: Text?)

    struct TextFieldExample: View {
        @State private var number: Double?
        var body: some View {
            TextField("Placeholder", value: $number, format: .number)
        }
    }
    

    In both of these, entering anything other than a number will cause the TextField to reject the input.

    Both of these methods will present a standard keyboard, if you want to make the UX better you could set the keyboardType to be .numberPad or .decimalPad. Just remember that if you use these keyboard types then you will need to add a button to the keyboard to dismiss you can do this using the .toolbar modifier and @FocusState, you'll also have to handle what happens when the user presses your toolbar button as onSubmit doesn't seem to be called when the FocusState is released.

    If you want to have an empty TextField, when the user hasn't entered anything then make sure that your Double value is optional. If you would rather it always has a value, make sure that your Double value is not optional.


    Previous answer

    One way to do it is that you can set the type of keyboard on the TextField which will limit what people can type on.

    TextField("Total number of people", text: $numOfPeople)
        .keyboardType(.numberPad)
    

    Apple's documentation can be found here, and you can see a list of all supported keyboard types here.

    However, this method is only a first step and is not ideal as the only solution:

    1. iPad doesn't have a numberPad so this method won't work on an iPad.
    2. If the user is using a hardware keyboard then this method won't work.
    3. It does not check what the user has entered. A user could copy/paste a non-numeric value into the TextField.

    You should sanitise the data that is entered and make sure that it is purely numeric.

    For a solution that does that checkout John M's solution below. He does a great job explaining how to sanitise the data and how it works.