Programmatically Setting Focus on SwiftUI Text Fields with FocusState

May 16th, 2025

⏱ Reading Time: 8 mins

Using text fields in our apps is pretty common; it's the way for users to input custom text. They often simply tap on the text field they want to type into, and the keyboard appears. But there are times where a text field must be selected programmatically without any user interaction. That's where things get interesting, as the first years of SwiftUI it was tricky to do that; introducing UIKit text fields in SwiftUI was the only option for developers. However, as of iOS 15, there's been a SwiftUI native way to programmatically control focus on text fields, the @FocusState property wrapper.

@FocusState makes it really easy to manage text field focus programmatically, but it might look a bit unclear how to put it in motion at first. In this post we'll get to know how to properly use it, no matter if there's a single, or many text fields in a view.


Focusing on a single text field

Let's get started with a simple SwiftUI view, where there is only a text field and a button:

The purpose is to make the text field active and present the keyboard just by tapping on the button. Managing that includes three distinct steps:

At first, we need to declare a property in the view, marked with the @FocusState property wrapper. Note that this property:

  • Does not have a type.
  • Does not have explicit initial value.

Consider isFocused as a Bool value with its initial value implicitly set to false by default. The name can be anything we want.

The second step is to toggle its value and make it true right where it's necessary to trigger the keyboard appearance. In this case, that's the action closure of the button:

Lastly, we need to apply a specific view modifier to the text field, called focused. As argument we provide the binding value of the isFocused property:

That's all it always takes to programmatically focus on a text field in SwiftUI using the @FocusState property wrapper. With the above additions, the initial view is updated like so:

To programmatically dismiss the keyboard, we just need to make the isFocused property false again. But on top of that, we can also use isFocused for conditional code execution, as you can see in the next addition to the view; a button to dismiss the keyboard appears if only isFocused is true:

Here's how all the above work:

Focusing on a text field when the view appears

Sometimes we want a text field to have the focus right when the view appears, so the keyboard appears instantly and users can start typing at once. For example, take a look at the following two views, where a navigation link in the first one navigates to the second that contains a text field:

See that the TextFieldView already contains a @FocusState property and the focused modifier applied on the text field.

At the moment, the keyboard does not show up automatically, nor the text field is activated when the view appears. However, managing that is as simple as it sounds; we just need to toggle the value of isFocused in the onAppear modifier. The latter is called right upon the view appearance.

With that in mind, we can update the TextFieldView by appending the onAppear modifier as shown next:

The text field now gains the focus automatically and the keyboard is presented right when the view appears:

Focusing on two text fields subsequently

SwiftUI views and forms often have more than one text fields, where it might be necessary to programmatically focus on one text field after the other. To talk in code, see the following example

The view contains two text fields, and two @FocusState properties respectively. The focused modifier is applied on each text field, getting as argument the binding value of the proper @FocusState property ($isFirstNameFocused and $isLastNameFocused).

It's made instantly clear here that it's perfectly fine for a view to contain two @FocusState properties. In fact, it's perfectly fine to contain any number of them. But when they become more than two or three, managing them starts to be difficult and risky.

☝️ Note:
There's a better way to manage multiple @FocusState properties for multiple text fields in the next part.

The view also contains the Next button. If no text view has the focus, this button will activate the first one. Otherwise, it will switch the focus between text fields simply by toggling the values of the @FocusState properties.

Let's add the code that will do all that:

Notice that the Next button is working as intended, and the two @FocusState properties have their values updated as needed. However, the keyboard does not remain constantly present, even though the text fields get the focus one after the other instantly. That kind of flickering can be annoying, but it can be avoided as described in the next part. In any case, it remains the fact here that we can perfectly have more than one @FocusState properties in a view.

☝️ Note:
Actually, it's possible to avoid flickering by setting true to both @FocusState properties simultaneously, instead of toggling them in the Next button:

isFirstNameFocused = true
isLastNameFocused = true


However, this might lead to unexpected behavior and I would avoid it. The following method is much better to get around any visual inconsistencies.

Focusing on multiple text fields

Managing multiple focus states when there are multiple text fields can become pretty hard, with messy and complicated code. However, things become straightforward if we use an enum with cases describing the text field that should have the focus, instead of multiple @FocusState properties.

To make that clear, let's see first the following SwiftUI view that contains multiple text fields:

Right now there aren't any @FocusState properties, but the Next button is present again. Its purpose is to rotate the focus from one text field to the other, but so far it does nothing at all.

To make it possible to programmatically give the focus to multiple text fields, we start by declaring an enum in the view as shown next:

The name of the enum can be anything. Notice that there are four cases, just as many as the text fields in the view. Moreover, each case name matches to a @State property, but note that it's not necessary to use similar names. I did it here for clarity reasons.

Next, we declare just one @FocusState property, following one rule; we explicitly set the enum type as its datatype, and we keep it optional:

After that, and just like we previously did, we'll apply the focused modifier on all text fields, but with an additional argument as you see next:

The focus(_:equals:) modifier checks if the current value of the focusedField is equal to the second argument (also an enum case), and if so, it gives the focus on the text field. But In order to make this comparison possible, the enum must conform to Hashable protocol, and simple enums like the FocusedField do so by default.

With all these additions, we can add now the missing functionality to the Next button. When it's tapped, it'll start from the first text field and will continue giving the focus on the next one in a rotation, simply by setting the appropriate value to focusedField property:

Finally, let's add another button to dismiss the keyboard. This one will be conditionally visible and will perform a specific task; to make focusedField nil again, so no text field is active and let the keyboard disappear:

The entire view implementation is the following:

Conclusion

Focusing programmatically either on a single, or multiple text fields in a view is a process that always requires the same series of steps. Through the previous parts you've met how to make them active without any user interaction, and how to also dismiss the keyboard programmatically. My advice is to always prefer the enum-based approach when the view contains more than one text fields, even when they're just two of them, unless there are specific reasons not to do that. If @FocusState has been confusing you, then I hope this post helped you figure out how to master it. Thanks for reading!


Stay Up To Date

Subscribe to my newsletter and get notifiied instantly when I post something new on SerialCoder.dev.

    We respect your privacy. Unsubscribe at any time.