SwiftUI: Switching Focus Between Text Fields
In iOS development, managing text field focus and enabling seamless navigation between multiple text fields is crucial for creating a smooth and intuitive user experience. In this article, we will explore how to achieve effortless focus switching in SwiftUI, making it easier for users to input data and interact with your app.

Understanding the Focus State
To manage focus in SwiftUI you should use the FocusState
property wrapper that is available starting from iOS 15.
FocusState
property wrapper handles several aspects:
- It tracks the currently focused view.
- It enables switching focus to a specific view.
- It allows for removing focus from all views, which leads to keyboard dismissal.
FocusState
property wrapper is used in conjunction with 2 modifiers:
focused(_:)
— modifies view by binding its focus state to the given Boolean state value. Use this modifier to cause the view to receive focus whenever the condition value is true. You can use this modifier to observe the focus state of a single view, or programmatically set and remove focus from the view.
struct ProfileView: View {
@State private var firstName: String = ""
@FocusState private var firstNameFieldIsFocused: Bool
var body: some View {
NavigationStack {
Form {
TextField("First Name", text: $firstName)
.focused($firstNameFieldIsFocused)
}
.onAppear {
firstNameFieldIsFocused = true
}
}
}
}
focused(_:equals:)
— modifies view by binding its focus state to the given state value. Use this modifier to cause the view to receive focus whenever the binding equals the value.
struct ProfileView: View {
enum FocusableField: Hashable {
case firstName, lastName, email
}
@State private var firstName: String = ""
@State private var lastName: String = ""
@State private var email: String = ""
@FocusState private var focusedField: FocusableField?
var body: some View {
NavigationStack {
Form {
TextField("First Name", text: $firstName)
.focused($focusedField, equals: .firstName)
TextField("Last Name", text: $lastName)
.focused($focusedField, equals: .lastName)
TextField("Email", text: $email)
.keyboardType(.emailAddress)
.focused($focusedField, equals: .email)
}
.onAppear {
focus = .firstName
}
}
}
}
Switching Focus between Text Fields
When implementing a form that requires users to input multiple pieces of information, such as a registration form or a checkout process, switching focus between text fields is crucial. It allows users to effortlessly move through each field, filling in the required information without the need to manually tap on the next field each time.
Let’s consider a sample app that will consist of “Profile” screen allowing users to enter first name, last name, and email.

By following this code sample you will learn how to:
- Focus on the first text field when the view appears.
- Switch focus to the next text field when the user presses a Return Key.
- Switch focus to a specific text field according to your logic.
struct ContentView: View {
enum FocusableField: Hashable, CaseIterable {
case firstName, lastName, email
}
@State private var firstName: String = ""
@State private var lastName: String = ""
@State private var email: String = ""
@FocusState private var focusedField: FocusableField?
var body: some View {
NavigationStack {
Form {
TextField("First Name", text: $firstName)
.focused($focusedField, equals: .firstName)
TextField("Last Name", text: $lastName)
.focused($focusedField, equals: .lastName)
TextField("Email", text: $email)
.keyboardType(.emailAddress)
.focused($focusedField, equals: .email)
}
.navigationTitle("Profile")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Save", action: save)
}
}
.onAppear(perform: focusFirstField)
.onSubmit(focusNextField)
}
}
private func focusFirstField() {
focusedField = FocusableField.allCases.first
}
private func focusNextField() {
switch focusedField {
case .firstName:
focusedField = .lastName
case .lastName:
focusedField = .email
case .email:
focusedField = nil
case .none:
break
}
}
private func save() {
if firstName.isEmpty {
focusedField = .firstName
} else if lastName.isEmpty {
focusedField = .lastName
} else if email.isEmpty {
focusedField = .email
} else {
// Save...
}
}
}
Thanks for reading! I hope you enjoyed the article. Subscribe to my Medium profile for more insightful content in the future.