View modifier for a custom hover effect in SwiftUI

In this article we will look into how to create a custom hover effect in SwiftUI and how to abstract this logic into a reusable view modifier.

As an example we'll take a tappable view that gets a pink background on hover. To detect if the user is hovering over a view, we can use onHover(perform:) method. We will save the current isHovered value into @State variable and use this variable to control the view's background.

struct EditView: View {
    @State private var isHovered = false
    
    var body: some View {
        Text("Edit")
        .padding()
        .onTapGesture {
            // some action
        }
        .background(isHovered ? Color.pink : Color.clear)
        .clipShape(
            RoundedRectangle(
                cornerRadius: 10,
                style: .continuous
            )
        )
        .onHover { isHovered in
            withAnimation {
                self.isHovered = isHovered
            }
        }
    }
}

If we have multiple views in our app that get pink background on hover, then we need to repeat this logic for all of them. It would be nicer to create a ViewModifier that holds all of this logic and can be applied to any of our views.

struct PinkBackgroundOnHover: ViewModifier {
    @State private var isHovered = false
    
    func body(content: Content) -> some View {
        content
        .background(isHovered ? Color.pink : Color.clear)
        .clipShape(
            RoundedRectangle(
                cornerRadius: 10,
                style: .continuous
            )
        )
        .onHover { isHovered in
            withAnimation {
                self.isHovered = isHovered
            }
        }
    }
}

extension View {
    func pinkBackgroundOnHover() -> some View {
        self.modifier(PinkBackgroundOnHover())
    }
}

Now we can just add our pinkBackgroundOnHover() modifier to any view in the app.

struct EditView: View {
    var body: some View {
        Text("Edit")
        .padding()
        .onTapGesture {
            // some action
        }
            
        .pinkBackgroundOnHover()
    }
}

You can get the example code for this article from our GitHub.