How it works
SubmitTriggers is an option set that names the kinds of user actions SwiftUI treats as a submission — most commonly pressing Return in a text field, but also confirming a search field. You pass it to the onSubmit(of:) modifier to declare which submit-capable controls in a view hierarchy should run your handler, and you pass it to submitScope(_:) to stop a submission from propagating past a boundary. Reach for it whenever you want a control's natural "commit" gesture to drive your code, rather than wiring up a separate button or watching for individual keystrokes.
Choose a trigger with the
.textand.searchoptionsSubmitTriggersconforms toOptionSet, so each value is one or more submission kinds. The.textoption matches the Return key in controls likeTextFieldandSecureField, while.searchmatches the submit gesture of a searchable field; you can combine them with array syntax ([.text, .search]). The example asks for.textso that pressing Return in theTextFieldcounts as a submission.React to submissions with
onSubmit(of:)The
onSubmit(of:)modifier takes aSubmitTriggersvalue and a closure, and runs that closure when a matching control inside the modified hierarchy is submitted. Here.onSubmit(of: .text)attaches to theTextFieldand updatesgreetingfrom the currentnamethe moment the user presses Return — no submit button required.Scope the trigger to the controls you mean
Because
onSubmit(of:)applies to every matching control in its subtree, place it where it should take effect. In the example it sits directly on theTextField, so only that field's Return key fires the handler; attaching it higher in theVStackwould catch submissions from any text control nested below.Stop propagation with
submitScope(_:)Submissions normally bubble up to the nearest matching
onSubmit(of:). To prevent that for a particular subtree — for instance an inner field that should not trigger an outer form's submit handler — wrap it insubmitScope(_:)with theSubmitTriggersyou want blocked. The single field in this demo needs no scoping, but the same.textvalue is what you would pass to contain it.
.onSubmit(of: .text) to .onSubmit(of: .search) and watch the handler stop firing on Return, since the TextField no longer matches the requested trigger.Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct SubmitTriggersDemo: View {
@State private var name = ""
@State private var greeting = "Type a name and press return"
var body: some View {
VStack(spacing: 16) {
TextField("Name", text: $name)
.textFieldStyle(.roundedBorder)
.onSubmit(of: .text) {
greeting = name.isEmpty ? "Hello!" : "Hello, \(name)!"
}
Text(greeting)
.font(.headline)
}
.padding()
}
}