SwiftUI TextField: Focused and Focus State


Introduced in iOS 15, Focused modifier along with FocusState property wrapper can help you manage focus on TextField. You can use this combination to cycle through TextFields and place better validation in place by asking users to enter all required information before moving forward.

To better understand, we will continue to work on email and confirm email TextFields. When the user taps on the return key, we will move focus to the next TextField(confirm email). We will create a FocusState variable called focusConfirm which will be set to true when the user taps on next(return key) while focus is on email TextField, .focused modifier on confirm email TextField will gain focus as soon as FocusState changes the value.
struct TextFieldExample: View {
    
    @State private var email = ""
    @State private var confirmEmail = ""
    @State private var borderColor: Color = .gray
    
    @FocusState private var focusConfirm: Bool
    
    var body: some View {
        VStack {
            
            Image("dt")
                .resizable()
                .frame(width: 100, height: 100)
                .clipShape(Circle())
                .shadow(color: Color.black, radius: 2, x: 1, y: 1)
                .overlay(Circle().stroke(Color.gray, lineWidth: 2))
HStack {
                Image(systemName: "person.crop.circle.fill")
                    .foregroundColor(.gray).font(.headline)
                TextField("Email", text: $email)
                    .keyboardType(.emailAddress)
                    .submitLabel(.next)
                    .onSubmit {
                        focusConfirm = true
                    }
            }
            .padding()
            .overlay(RoundedRectangle(cornerRadius: 8).stroke(borderColor, lineWidth: 1))
            .padding(.horizontal)
        
            HStack {
                Image(systemName: "person.crop.circle.badge.checkmark")
                    .foregroundColor(.gray).font(.headline)
                TextField("Confirm email", text: $confirmEmail)
                    .keyboardType(.emailAddress)
                    .disabled(email.isEmpty)
                    .onSubmit {
                        validateEmail()
                    }
                    .submitLabel(.done)
                    .focused($focusConfirm)
            }
            .padding()
            .overlay(RoundedRectangle(cornerRadius: 8).stroke(borderColor, lineWidth: 1))
            .padding(.horizontal)
        }
    }
    
    private func validateEmail() {
        if email.localizedCaseInsensitiveCompare(confirmEmail) == .orderedSame {
            borderColor = .green
        } else {
            borderColor = .red
        }
    }
}