Apple unveiled SwiftUI - a UI framework for native iOS development back in 2019. Since then it has improved quite a lot and while some may (me included) still think that it has still long way to go however, annual updates to SwiftUI has made it immensely powerful and is now closer than ever to reach that point of completion.

One thing that used to irritate me quite a lot was that we had no way to make a textfield a first responder in the responder chain. This led to bad UX and you had to either go for a UIKit wrapper or looked for ways to bypass the need for making a textfield focused. However, Apple has now finally listened to us and provided an API to make a textfield first responder programmatically. This new API is called FocusedState.

FocusedState is a property wrapper. So start off my writing this bit code in ContentView struct:

  @FocusState private var loginFieldFocus: LogInField?

The property loginFieldFocus is of type enum LogInField. So let’s create an enum:

  enum LogInField {
      case username
      case password
  }

Now let’s quickly create two textfields and a button:

          VStack {
            TextField("Username", text: $username)
                .focused($loginFieldFocus, equals: .username)

            SecureField("Password", text: $password)
                .focused($loginFieldFocus, equals: .password)


            Button("Submit") {
                if username.isEmpty {
                    loginFieldFocus = .username
                }else if password.isEmpty {
                    loginFieldFocus = .password
                }
            }

            Spacer()
        }
  

In the V-Stack we have two textfields (one being a SecureField) for password entry and then a “Submit” button. Now let’s talk about the .focused modifier that we have added to the textfields.

    .focused($loginFieldFocus, equals: .username)
  

We are adding this modifier to the username textfield where we are assigning the FocusedState for that particular textfield to our enum case of ‘username’. We are doing the same for the password textfield as well. So now whenever we have to bring any of the two textfields to focus we can just assign the FocusedState to that particular enum case and the textfield will be focused. For example, when we press the Submit button, I do a simple check to see if any of the two textfields are empty, if they are then the corresponding textfield gets in focus.

    if username.isEmpty {
        loginFieldFocus = .username
    }else if password.isEmpty {
        loginFieldFocus = .password
    }

Another thing I would like to mention here is the fact that most of the time we want a textfield to get in focused as soon as the view appears. You can use the .onAppear modifier to assign the FocusedState property the textfield case. However, we need to add a bit of a delay of around 0.2, 0.3 seconds after the view appears. Here’s how:

        .onAppear {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                loginFieldFocus = .username
            }
        }
  

There is another way to focus a certain textfield and thats just by injecting a boolean value. Let’s take a look at it as well:

Again create a FocusState property but this time it shall be a Boolean value

  @FocusState private var fieldFocus: Bool

In this case, I am assigning fieldFocus to just password textfield. So I have removed the .focused modifier from username and I have added the following modifier to the SecureField:

    TextField("Username", text: $username)
    SecureField("Password", text: $password)
            .focused($fieldFocus)
  

Now inside the Submit button action clause, I am checking if the password which has been added has a count of less than 8, in which case it will focus the password field again for you to rewrite the password:

    Button("Submit") {
        if password.count < 8 {
            fieldFocus = true
        }else {
            //
        }
      }