Forms and input

SwiftUI forms: TextField

Learn how to use the TextField control in SwiftUI to get text input, bind it to State, configure the keyboard, handle submit, and manage focus.

The first form control we’ll see is the simplest one: TextField.

It shows some text, like the Text view does, but the user can edit it. That’s how we get text input.

Here’s the most basic TextField:

struct ContentView: View {
    @State private var name = ""
    
    var body: some View {
        Form {
            TextField("", text: $name)
        }
    }
}

The name property is a SwiftUI property wrapped with @State, so the view can update it. The $ prefix passes a binding: the text field writes into name every time the user types a character.

Run the code. You see an empty text field, and you can tap on it:

Xcode showing SwiftUI TextField code with iOS simulator displaying an empty text field in a form

Type something and it shows up in the field:

iOS simulator showing the text field with user input text displaying the word test

The first argument of TextField is the placeholder, a string shown when the field is empty. Use it to tell the user what goes in the field:

TextField("Your name", text: $name)

iOS simulator displaying a text field with Your name placeholder text visible

Styling

Inside a Form, the row styling comes for free. Outside of one, a text field has no visible border, which looks odd. Add one with textFieldStyle():

TextField("Your name", text: $name)
    .textFieldStyle(.roundedBorder)
    .padding()

Configuring the keyboard

For specific kinds of input you want the right keyboard, and you want iOS to stop “helping”. An email field is the classic case:

TextField("Email", text: $email)
    .keyboardType(.emailAddress)
    .textInputAutocapitalization(.never)
    .autocorrectionDisabled()

keyboardType(.emailAddress) puts @ and . on the main keyboard. textInputAutocapitalization(.never) stops iOS from capitalizing the first letter. autocorrectionDisabled() keeps autocorrect from mangling addresses.

I add these three lines to every email field. Without them users end up with Flavio@Gmail.com and a red validation error they don’t understand.

Handling submit

When the user presses return, the onSubmit closure runs. You can also change what the return key says with submitLabel():

TextField("Search", text: $query)
    .submitLabel(.search)
    .onSubmit {
        performSearch()
    }

Now the return key reads “Search”, and pressing it calls your function.

Passwords

For sensitive input use SecureField. Same API, but the characters show as dots and the text stays out of screenshots and screen recordings:

SecureField("Password", text: $password)

Controlling focus

Sometimes you want the keyboard to appear as soon as a screen shows up, without waiting for a tap. That’s what @FocusState is for:

struct ContentView: View {
    @State private var name = ""
    @FocusState private var isFocused: Bool

    var body: some View {
        Form {
            TextField("Your name", text: $name)
                .focused($isFocused)
        }
        .onAppear {
            isFocused = true
        }
    }
}

Setting isFocused to true in code focuses the field and raises the keyboard. Setting it to false dismisses it. Focus becomes just another piece of state, which fits the rest of SwiftUI nicely.

Lesson completed