Skip to content

Custom Hover Effects (SwiftUI)

A SwiftUI guide for coding agents. Also covers hovereffect modifier, visionos hover effect, customhovereffect protocol, scale on hover ios, gaze highlight visionos, hover animation delay.

The hoverEffect closure modifier builds a custom reaction for when the user looks at a view on visionOS, or points at it on macOS and tvOS. A CustomHoverEffect type makes the effect reusable.

The hoverEffect closure

The closure works like visualEffect. It hands you an empty effect stub to chain effects onto, an isActive flag that turns true while the user hovers, and a GeometryProxy for the view's geometry.

Button("Play", systemImage: "play.fill") { }
  .labelStyle(.iconOnly)
  .hoverEffect { effect, isActive, geometry in
    effect.scaleEffect(isActive ? 1.1 : 1.0)
  }

Delay the effect with animation

Many hover effects firing as the user looks around clutters the experience. Call animation on the effect stub to delay activation, which matters most when the effect changes the view's size.

.hoverEffect { effect, isActive, geometry in
  effect.animation(.default.delay(isActive ? 0.8 : 0.2)) {
    $0.scaleEffect(isActive ? 1.1 : 1.0)
  }
}

Reuse with CustomHoverEffect

Wrap the closure in a type that conforms to CustomHoverEffect. The only requirement is a body(content:) function, and the closure body moves in unchanged.

struct ScaleEffect: CustomHoverEffect {
  func body(content: Content) -> some CustomHoverEffect {
    content.hoverEffect { effect, isActive, geometry in
      effect.animation(.default) {
        $0.scaleEffect(isActive ? 1.1 : 1.0)
      }
    }
  }
}

// usage
.hoverEffect(ScaleEffect())

Use this guidance in your coding agent

Install the Better Design MCP once. Your agent then loads this page with one call.

get-swiftui-guide({ topic: "swiftui-custom-hover-effects" })
claude mcp add --scope user better-design --transport http https://better-design.com/api/mcp --header "Authorization: Bearer <YOUR_API_KEY>"
Browse related design systems