Hover Reveal Override for Framer

Copy component

Hover Reveal Override for Framer

Copy component

Nandi Muzsik

How can I improve Framer Uni?

Let me know if there’s a missing feature or something that could be improved.

Share feedback

Nandi Muzsik

How can I improve Framer Uni?

Let me know if there’s a missing feature or something that could be improved.

Share feedback

Effect

Hover Reveal Override for Framer

This is a hover reveal effect, originally created by Matt Parry. I've turned it into a code override that works seamlessly in Framer, making it simple to apply to any element on your Framer website.

image of Nandi Muzsik
profile image of Matt Perry

Created by

Hover Reveal Override for Framer
Hover Reveal Override for Framer
Hover Reveal Override for Framer

About the resource

You can either copy the component and use the hover reveal effect with an image, or just copy the code override to create the override yourself in your Framer project and apply it to any element.

In this demo, I employed the hover reveal override in such a way that there's a separate image layer beneath the hover reveal image. It's set to 0.1 opacity, so you can still see the image even if it isn't fully revealed.

Code override for hover reveal effect

Feel free to copy the override code from below and create the override yourself in your Framer project.

About the resource

You can either copy the component and use the hover reveal effect with an image, or just copy the code override to create the override yourself in your Framer project and apply it to any element.

In this demo, I employed the hover reveal override in such a way that there's a separate image layer beneath the hover reveal image. It's set to 0.1 opacity, so you can still see the image even if it isn't fully revealed.

Code override for hover reveal effect

Feel free to copy the override code from below and create the override yourself in your Framer project.

About the resource

You can either copy the component and use the hover reveal effect with an image, or just copy the code override to create the override yourself in your Framer project and apply it to any element.

In this demo, I employed the hover reveal override in such a way that there's a separate image layer beneath the hover reveal image. It's set to 0.1 opacity, so you can still see the image even if it isn't fully revealed.

Code override for hover reveal effect

Feel free to copy the override code from below and create the override yourself in your Framer project.

import type { ComponentType } from "react"
import { useEffect, useState, useRef } from "react"
import {
    animate,
    motion,
    useMotionValue,
    useMotionTemplate,
} from "framer-motion"

export function withImageMask(Component): ComponentType {
    return (props) => {
        const [size, setSize] = useState<
            { width: number; height: number } | undefined
        >(undefined)
        const maskX = useMotionValue(0)
        const maskY = useMotionValue(0)
        const maskSize = useMotionValue(0)
        const maskImage = useMotionTemplate`radial-gradient(circle at ${maskX}px ${maskY}px, black ${maskSize}px, transparent ${maskSize}px)`
        const ref = useRef(null)

        useEffect(() => {
            if (!size || !ref.current) return

            const transition = {
                type: "spring",
                stiffness: 200,
                damping: 10,
            }

            const { width, height } = size
            animate(maskSize, Math.sqrt(width * width + height * height), {
                duration: 0.7,
            })
            animate(maskX, width / 2, transition)
            animate(maskY, height / 2, transition)
        }, [size])

        return (
            <motion.div
                ref={ref}
                onHoverStart={() => !size && animate(maskSize, 50)}
                onHoverEnd={() => !size && animate(maskSize, 0)}
                onPointerDown={() => !size && animate(maskSize, 40)}
                onClick={() => setSize(ref.current.getBoundingClientRect())}
                onPointerMove={(e) => {
                    if (size) return
                    const { top, left } = ref.current.getBoundingClientRect()
                    maskX.set(e.clientX - left)
                    maskY.set(e.clientY - top)
                }}
                style={{ WebkitMaskImage: maskImage, maskImage }}
                {...props}
            >
                <Component {...props} />
            </motion.div>
        )
    }
}
import type { ComponentType } from "react"
import { useEffect, useState, useRef } from "react"
import {
    animate,
    motion,
    useMotionValue,
    useMotionTemplate,
} from "framer-motion"

export function withImageMask(Component): ComponentType {
    return (props) => {
        const [size, setSize] = useState<
            { width: number; height: number } | undefined
        >(undefined)
        const maskX = useMotionValue(0)
        const maskY = useMotionValue(0)
        const maskSize = useMotionValue(0)
        const maskImage = useMotionTemplate`radial-gradient(circle at ${maskX}px ${maskY}px, black ${maskSize}px, transparent ${maskSize}px)`
        const ref = useRef(null)

        useEffect(() => {
            if (!size || !ref.current) return

            const transition = {
                type: "spring",
                stiffness: 200,
                damping: 10,
            }

            const { width, height } = size
            animate(maskSize, Math.sqrt(width * width + height * height), {
                duration: 0.7,
            })
            animate(maskX, width / 2, transition)
            animate(maskY, height / 2, transition)
        }, [size])

        return (
            <motion.div
                ref={ref}
                onHoverStart={() => !size && animate(maskSize, 50)}
                onHoverEnd={() => !size && animate(maskSize, 0)}
                onPointerDown={() => !size && animate(maskSize, 40)}
                onClick={() => setSize(ref.current.getBoundingClientRect())}
                onPointerMove={(e) => {
                    if (size) return
                    const { top, left } = ref.current.getBoundingClientRect()
                    maskX.set(e.clientX - left)
                    maskY.set(e.clientY - top)
                }}
                style={{ WebkitMaskImage: maskImage, maskImage }}
                {...props}
            >
                <Component {...props} />
            </motion.div>
        )
    }
}
import type { ComponentType } from "react"
import { useEffect, useState, useRef } from "react"
import {
    animate,
    motion,
    useMotionValue,
    useMotionTemplate,
} from "framer-motion"

export function withImageMask(Component): ComponentType {
    return (props) => {
        const [size, setSize] = useState<
            { width: number; height: number } | undefined
        >(undefined)
        const maskX = useMotionValue(0)
        const maskY = useMotionValue(0)
        const maskSize = useMotionValue(0)
        const maskImage = useMotionTemplate`radial-gradient(circle at ${maskX}px ${maskY}px, black ${maskSize}px, transparent ${maskSize}px)`
        const ref = useRef(null)

        useEffect(() => {
            if (!size || !ref.current) return

            const transition = {
                type: "spring",
                stiffness: 200,
                damping: 10,
            }

            const { width, height } = size
            animate(maskSize, Math.sqrt(width * width + height * height), {
                duration: 0.7,
            })
            animate(maskX, width / 2, transition)
            animate(maskY, height / 2, transition)
        }, [size])

        return (
            <motion.div
                ref={ref}
                onHoverStart={() => !size && animate(maskSize, 50)}
                onHoverEnd={() => !size && animate(maskSize, 0)}
                onPointerDown={() => !size && animate(maskSize, 40)}
                onClick={() => setSize(ref.current.getBoundingClientRect())}
                onPointerMove={(e) => {
                    if (size) return
                    const { top, left } = ref.current.getBoundingClientRect()
                    maskX.set(e.clientX - left)
                    maskY.set(e.clientY - top)
                }}
                style={{ WebkitMaskImage: maskImage, maskImage }}
                {...props}
            >
                <Component {...props} />
            </motion.div>
        )
    }
}

Framer Navigator

Learn the fundamentals of Framer for free.

Build your ideas with ease by learning the basics of website building with Framer.

Nandi portrait's background
Nandi's portrait

Framer Navigator

Learn the fundamentals of Framer for free.

Build your ideas with ease by learning the basics of website building with Framer.

Nandi portrait's background
Nandi's portrait

Framer Navigator

Learn the fundamentals of Framer for free.

Build your ideas with ease by learning the basics of website building with Framer.

Nandi portrait's background
Nandi's portrait

More resources

More resources

  • Interactive Isometric 3D Hero

    Interactive Isometric 3D Hero

    Effect

    Interactive Isometric 3D Hero

    Interactive Isometric 3D Hero

    Effect

    Interactive Isometric 3D Hero

    Interactive Isometric 3D Hero

    Effect

  • Show Once Code Override for Framer

    Show Once Code Override for Framer

    Effect

    Show Once Code Override for Framer

    Show Once Code Override for Framer

    Effect

    Show Once Code Override for Framer

    Show Once Code Override for Framer

    Effect