NEW: Start my new Ultimate Portfolio App course with a free Hacking with Swift+ trial! >>

Reading text from the user with TextField

Paul Hudson    @twostraws   

We’re building a check-splitting app, which means users need to be able to enter the cost of their check, how many people are sharing the cost, and how much tip they want to leave.

Hopefully already you can see that means we need to add three @State properties, because there are three pieces of data we’re expecting users to enter into our app.

So, start by adding these three properties to our ContentView struct:

@State private var checkAmount = ""
@State private var numberOfPeople = 2
@State private var tipPercentage = 2

As you can see, that gives us an empty string for the check amount, a default value of 2 for the number of people, and a default value of 2 for the tip percentage.

You might wonder why we’re using strings for the check amount, when clearly an Int or Double would work better. Well, the reason is that we have no choice: SwiftUI must use strings to store text field values.

Having two people be the default for splitting a check is sensible - it won’t be right a lot of the time, but it’s still a good default. But having a tip percentage of 2 might seem odd: do we really intend to leave a 2% tip?

Well, no. Instead, we’re using 2 here because we’re going to use that to select values from a predetermined array of tip sizes, so you can see different picker styles in action.

We need to store the list of possible tip sizes somewhere, so please add this fourth property beneath the previous three:

let tipPercentages = [10, 15, 20, 25, 0]

Now you can see that a tip percentage of 2 actually means a 20% tip, because that’s the values of tipPercentages[2].

We’re going to build up the form step by step, starting with a text field where users can enter the value of their check.

Modify the body property to this:

var body: some View {
    Form {
        Section {
            TextField("Amount", text: $checkAmount)

That will create a scrolling entry form of one section, which in turn contains one row: our text field. When you create text fields in forms, the first parameter is a string that gets used as the placeholder – gray text shown in side the text field, giving users an idea of what should be in there. The second parameter is the two-way binding to our checkAmount property, which means as the user types that property will be updated.

One of the great things about the @State property wrapper is that it automatically watches for changes, and when something happens it will automatically re-invoke the body property. That’s a fancy way of saying it will reload your UI to reflect the changed state, and it’s a fundamental feature of the way SwiftUI works.

To demonstrate this, add a second section with a text view showing the value of checkAmount, like this:

Form {
    Section {
        TextField("Amount", text: $checkAmount)

    Section {

We’ll be making that show something else later on, but for now please run the app in the simulator so you can try it yourself.

Tap on the check amount text field, then enter some text – it doesn’t need to be a number; anything will do. What you’ll see is that as you type the text view in the second section automatically and immediately reflects your actions.

This synchronization happens because:

  1. Our text field has a two-way binding to the checkAmount property.
  2. The checkAmount property is marked with @State, which automatically watches for changes in the value.
  3. When an @State property changes SwiftUI will re-invoke the body property (i.e., reload our UI)
  4. Therefore the text view will get the updated value of checkAmount.

The final project won’t show checkAmount in that text view, but it’s good enough for now. Before we move on, though, I want to address one important problem: when you tap to enter text into our text field, users see a regular alphabetical keyboard. Sure, they can tap a button on the keyboard to get to the numbers screen, but it’s annoying and and not really necessary.

Fortunately, text fields have a modifier that lets us force a different kind of keyboard: keyboardType(). We can give this a parameter specifying the kind of keyboard we want, and in this instance either .numberPad or .decimalPad are good choices. Both of those keyboards will show the digits 0 through 9 for users to tap on, but .decimalPad also shows a decimal point so users can enter check amount like $32.50 rather than just whole numbers.

So, modify your text field to this:

TextField("Amount", text: $checkAmount)

You’ll notice I added a line break before .keyboardType and also indented it one level deeper than TextField – that isn’t required, but it can help you keep track of which modifiers apply to which views.

Go ahead and run the app now and you should find you can now only type numbers into the text field.

Tip: The .numberPad and .decimalPad keyboards types tell SwiftUI to show the digits 0 through 9 and optionally also the decimal point, but that doesn’t stop users from entering other values. For example, if they have a hardware keyboard they can type what they like, and if they copy some text from elsewhere they’ll be able to paste that into the text field no matter what is inside that text. That’s OK, though – we’ll be handling that eventuality later.

Hacking with Swift is sponsored by RevenueCat

SPONSORED Building and maintaining in-app subscription infrastructure is hard. Luckily there's a better way. With RevenueCat, you can implement subscriptions for your app in hours, not months, so you can get back to building your app.

Try it for free

Sponsor Hacking with Swift and reach the world's largest Swift community!

Buy Pro Swift Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift (Vapor Edition) Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Server-Side Swift (Kitura Edition) Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.9/5

Unknown user

You are not logged in

Log in or create account

Link copied to your pasteboard.