Customizing Keyboard submit button in SwiftUI | SwiftUI Bootcamp #61
The blue "Return" key on an iOS keyboard can say many things — "Search", "Next", "Done", "Go" — and matching that label to your field's purpose makes the interface feel polished and intentional. This lesson shows you how to set the label with submitLabel and respond to it with onSubmit.
What You'll Learn
- How to use
.submitLabel(_:)to change the keyboard's return key label - The full list of available
SubmitLabelvalues and when to use each - How to combine
.submitLabelwith.onSubmitto take action when the user taps the key
Mental Model
Imagine you're filling out a paper form. At the end of the username box it says "Go to password →", and at the end of the password box it says "Submit". Each field has a different instruction for what happens next. .submitLabel is how you add those instructions to the virtual keyboard — it sets the text on the return key so users know what pressing it will do, without reading any other UI.
The key insight is that the label is purely cosmetic from SwiftUI's perspective. Whether you show "Search" or "Done", the underlying event is the same keyboard return action. The label manages user expectations; onSubmit is where you actually respond.
Detailed Explanation
.submitLabel(_:) is a modifier available since iOS 15 that accepts a SubmitLabel value and changes the text shown on the keyboard's return key. The available options are: .done, .go, .join, .next, .route, .search, .send, .return, and .continue. Apple maps these to localized strings automatically, so your app works correctly in different languages without extra work.
Under the hood, this modifier communicates with UIKit's UIReturnKeyType — SwiftUI translates the SubmitLabel to the correct UIReturnKeyType value when creating the underlying UITextField. This means the behavior is consistent with what UIKit developers already know.
.onSubmit is the companion modifier that fires when the user presses the submit key. It receives no arguments — if you need to know which field triggered it, use @FocusState alongside it to check the current focus state. Always pair .submitLabel with .onSubmit when you want the key to do something meaningful; without onSubmit, the key just dismisses the keyboard.
Use .submitLabel(.next) when you want to advance the user to the next field in a form. Use .submitLabel(.search) for search bars. Use .submitLabel(.done) or .submitLabel(.go) for final submission actions. Avoid .submitLabel(.return) in most cases — it provides no context to the user about what happens next.
Code Structure
SubmitTextFieldBootcamp.swift shows three TextField instances, each with a different submitLabel. This side-by-side comparison lets you run the app and immediately see how each label looks on the keyboard, making it easy to choose the right one for your own fields.
Complete Code
SubmitTextFieldBootcamp.swift
import SwiftUI
struct SubmitTextFieldBootcamp: View {
@State private var text: String = ""
var body: some View {
VStack {
TextField("Placeholder...", text: $text)
.submitLabel(.route) // Shows "Route" on the keyboard return key
.onSubmit {
print("Something to the console!")
}
TextField("Placeholder...", text: $text)
.submitLabel(.next) // Shows "Next" — ideal for advancing through form fields
.onSubmit {
print("Something to the console!")
}
TextField("Placeholder...", text: $text)
.submitLabel(.search) // Shows "Search" — standard label for search inputs
.onSubmit {
print("Something to the console!")
}
}
}
}
struct SubmitTextFieldBootcamp_Previews: PreviewProvider {
static var previews: some View {
SubmitTextFieldBootcamp()
}
}Code Walkthrough
@State private var text: String = ""— All three fields share one@Statestring here for simplicity. In a real form, each field would have its own@Statevariable so the values are independent..submitLabel(.route)— Sets the keyboard return key to read "Route". This is appropriate in navigation or directions apps where the action of submitting leads to a route calculation..submitLabel(.next)— The most common label for multi-field forms. It signals to the user that pressing the key will move them forward in the form rather than submit it. In a real form, the.onSubmitclosure would update@FocusStateto the next field..submitLabel(.search)— Turns the return key into a "Search" key, matching the convention in search bars. The.onSubmitclosure is where you would trigger your search logic..onSubmit { ... }— This closure fires every time the user presses the labeled return key. Since all three fields use the same closure here (just a print), in real code you would put different actions for each field, or use@FocusStateto determine which field was active and branch accordingly.
Common Mistakes
Mistake: Using .submitLabel without .onSubmit
Changing the label but not handling the action is misleading. If you label a key "Search" but pressing it only dismisses the keyboard, users will be confused. Always pair a meaningful label with a matching action in onSubmit.
Mistake: Thinking .submitLabel changes keyboard behavior, not just appearance
The label is cosmetic — .submitLabel(.done) doesn't automatically dismiss the keyboard or validate the field. You must handle the dismissal or field advancement yourself in the onSubmit closure. A common pattern is setting @FocusState to nil in onSubmit to dismiss the keyboard.
Mistake: Forgetting that onSubmit fires for all nested text fieldsonSubmit is inherited — placing it on a container view (like a VStack) means it fires for any text field inside that container. This is a powerful pattern but can be surprising. If you want per-field behavior, attach onSubmit directly to each field.
Key Takeaways
.submitLabel(_:)sets the text on the keyboard's return key — choose one that matches the action the field performsonSubmitis the action handler that pairs withsubmitLabel— without it, the label change has no functional effect- For multi-step forms, combine
.submitLabel(.next)with@FocusStateto automatically advance the user through fields
Last updated: June 27, 2026