Guiding Users with a Pulsating Button
When building an onboarding flow, one challenge is directing the user’s attention to the next action they should take. A subtle pulsating animation on buttons draws the eye without being intrusive. I implemented this in SwiftUI using a combination of scaleEffect and opacity modifiers tied to a repeating animation.
Here is the core approach:
struct PulsatingButtonStyle: ButtonStyle {
@State private var isPulsating = false
func makeBody(configuration: Configuration) -> some View {
configuration.label
.scaleEffect(isPulsating ? 1.06 : 1.0)
.opacity(isPulsating ? 0.8 : 1.0)
.animation(
.easeInOut(duration: 0.8)
.repeatForever(autoreverses: true),
value: isPulsating
)
.onAppear {
isPulsating = true
}
}
}The trick is combining two animations – scale and opacity – that run in sync. The repeatForever(autoreverses: true) modifier makes the animation bounce back and forth continuously. By toggling isPulsating on appear, the animation starts immediately when the view is displayed.
The scale factor of 1.06 is intentionally subtle. Going much higher (like 1.2) makes the animation feel aggressive and distracting. The slight opacity shift adds depth to the pulse without making the button hard to read.
This pattern works well for onboarding screens where you want to highlight a “Continue” or “Get Started” button. Once the user has moved past onboarding, the animation is no longer shown, so it does not become annoying over time.
You can apply it to any button with .buttonStyle(PulsatingButtonStyle()), keeping the animation logic cleanly separated from your button content.
