Lab 050 – Hover Effect Namespace
Show and hide a symbol with a hover effect, using the shape of the parent view to trigger the effect.
Overview
I want a way to show a hover effect that doesn’t impact the content of the view being hovered. For example, in Looming Deadlines I’m considering a grid of countdown timers. Each one could have custom backgrounds (colors, gradients, maybe even photos). I don’t want to apply visual changes to that background. I want to show something when the view is hovered–some sort of indicator that tapping the view will do something.
What I came up with is a way to show and hide an image/symbol when the parent view is hovered. This is a bit of a hack, but it works. I have a custom view for my grid cell. In that view, I added a namespace that we can use in the hover effects.
@Namespace private var hoverNamespaceThis view is a ZStack with a shape and an image. On the image I added a hover effect using the namespace. Whenever any effects using this namespace are hovered, we’ll chang the opacity of this image.
Image(systemName: "star.fill")
.hoverEffect(in: HoverEffectGroup(hoverNamespace)) { effect, isActive, _ in
effect.opacity(isActive ? 1.0 : 0)
}On the outer ZStack, I did something similar. I didn’t want to apply a visual change to the ZStack or shape, so I needed to return an effect that does nothing. The hacky part is that we can just return the effect.
ZStack {}
.hoverEffect(in: HoverEffectGroup(hoverNamespace)) { effect, _, _ in
effect
}Here it is in practice:
Lab Code
struct Lab050: View {
var body: some View {
HStack(spacing: 12) {
ShapeHoverDemo(color: .stepRed)
ShapeHoverDemo(color: .stepGreen)
ShapeHoverDemo(color: .stepBlue)
}
.padding()
}
}
private struct ShapeHoverDemo: View {
// 1. Create a namespace
@Namespace private var hoverNamespace
@State var color: Color = .stepRed
var body: some View {
ZStack {
Rectangle()
.foregroundStyle(color)
Image(systemName: "star.fill")
.foregroundColor(.white)
.font(.largeTitle)
// 2. Use HoverEffectGroup with the namespace we defined above
.hoverEffect(in: HoverEffectGroup(hoverNamespace)) { effect, isActive, proxy in
effect.opacity(isActive ? 1.0 : 0)
}
}
// 2. Use HoverEffectGroup with the namespace we defined above
.hoverEffect(in: HoverEffectGroup(hoverNamespace)) { effect, isActive, proxy in
// Hack: just return the effect without applying it to any view
// This let's us use the shape of the ZStack to receive hover focus, without applying a visual change to it
effect
}
.aspectRatio(4/3, contentMode: .fit)
.clipShape(.rect(cornerRadius: 24))
}
}Support our work so we can continue to bring you new examples and articles.
Download the Xcode project with this and many more labs from Step Into Vision.

Follow Step Into Vision