The sensoryFeedback view modifier plays haptic feedback when a trigger value changes, on every
Apple platform. Attach it to any view: no UIFeedbackGenerator, no UIKit bridge.
Style Plus Trigger
The basic form takes a feedback style and a trigger value. SwiftUI plays the haptic whenever the trigger value changes.
struct ContentView: View {
@State private var store = Store()
var body: some View {
NavigationStack {
List(store.results, id: \.self) { result in
Text(result)
}
.searchable(text: $store.query)
.sensoryFeedback(.success, trigger: store.results)
}
}
}
Predefined styles include success, warning, error, selection, increase, decrease,
start, stop, alignment, levelChange, and impact.
Tuning Impact
The impact style takes weight and intensity arguments. Prefer a predefined style; reach for
a tuned impact only when no semantic style fits.
Button("Action") {
trigger.toggle()
}
.sensoryFeedback(
.impact(weight: .heavy, intensity: 0.9),
trigger: trigger
)
Choosing the Style From the Change
A closure variant receives the old and new trigger values and returns the style to play, or nil
to stay silent. Use it when one state change maps to different outcomes.
.sensoryFeedback(trigger: store.results) { oldValue, newValue in
newValue.isEmpty ? .error : .success
}
A second closure variant keeps a fixed style but gates it with a condition on the change.
.sensoryFeedback(.success, trigger: store.results) { oldValue, newValue in
newValue.isEmpty
}
When to Play Haptics
Do not fire a haptic on every change. Reserve them for significant task results and accessibility cues, or the feedback loses its meaning and starts to annoy.