TechnologiesSwiftUIHover and Pointer Effects

GroupHoverEffect struct

iOSmacOStvOSwatchOSvisionOS✓ renders

A `CustomHoverEffect` that activates a named group of effects.

How it works

GroupHoverEffect is a hover effect that treats several views as a single interactive unit, so a pointer entering any part of the group animates them all at once rather than highlighting each subview independently. Reach for it when a cluster of views — a row of labels, a card, a toolbar segment — should read as one target under the pointer on iPadOS, where a connected hardware pointer drives hover. Because the effect coordinates the whole group, you get a unified lift, highlight, or shape morph instead of a patchwork of separate responses.

  1. Apply the effect with hoverEffect(_:)

    You attach a GroupHoverEffect through the hoverEffect(_:) modifier placed on the container that bounds the group. In the example, .hoverEffect(.lift) sits on the VStack so the pointer interacts with the two Label views as one element. Putting the modifier on the enclosing view — not on each child — is what makes the response group-wide.

  2. Choose the built-in effect style

    The argument selects which hover treatment the group performs. .lift raises and subtly scales the content while morphing its background toward the pointer; .highlight tints in place; and .automatic lets the system pick. Here .lift lifts the whole label stack together, giving the cluster a single coordinated motion.

  3. Shape the effect with the group's background

    The hover effect follows the visual bounds of the view it's applied to, so the surrounding shape defines the silhouette that lifts and highlights. In the example, .background(.quaternary, in: RoundedRectangle(cornerRadius: 12)) gives the group a rounded card, and the .lift effect honors that RoundedRectangle corner radius as it animates. Padding before the background sets how much of the content the effect encloses.

  4. Keep the effect inside the group's bounds

    Because GroupHoverEffect is scoped to the modified view's frame, the inner .padding() (applied before .background) widens the hit and highlight region around the labels, while the trailing .padding() only spaces the card from its surroundings. Only what falls within the view carrying hoverEffect(.lift) participates in the shared response.

Try it — Change .hoverEffect(.lift) to .hoverEffect(.highlight) to see the whole label group tint together in place instead of lifting as one raised card.

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.

GroupHoverEffect.swift
struct GroupHoverEffectDemo: View {
    var body: some View {
        VStack(spacing: 12) {
            Label("Favorites", systemImage: "star.fill")
            Label("Recents", systemImage: "clock.fill")
        }
        .font(.headline)
        .padding()
        .background(.quaternary, in: RoundedRectangle(cornerRadius: 12))
        .hoverEffect(.lift)
        .padding()
    }
}
Live preview
Favorites Recents
Favorites Recents
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →