Custom Cursor Override

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

Custom Cursor Override

This is a code override you can use to create a custom "circle" cursor for your Framer website. This effect was inspired by the amazing website of Eythan D'Amico.

image of Nandi Muzsik

Created by

Custom Cursor Override
Custom Cursor Override
Custom Cursor Override
custom cursor in Framer

Related Blog Post

How To Create A Custom Cursor In Framer

custom cursor in Framer

Related Blog Post

How To Create A Custom Cursor In Framer

custom cursor in Framer

Related Blog Post

How To Create A Custom Cursor In Framer

About the resource

You can create a "Custom Cursor" frame and apply the code override you find below. This will turn that frame into your cursor on the website.

Check out the full guide about the implementation here.

Custom cursor code override

Here's the code you need to copy and create a code override file in your project. Afterward, just apply that code override to your cursor frame to transform it into your custom cursor.

About the resource

You can create a "Custom Cursor" frame and apply the code override you find below. This will turn that frame into your cursor on the website.

Check out the full guide about the implementation here.

Custom cursor code override

Here's the code you need to copy and create a code override file in your project. Afterward, just apply that code override to your cursor frame to transform it into your custom cursor.

About the resource

You can create a "Custom Cursor" frame and apply the code override you find below. This will turn that frame into your cursor on the website.

Check out the full guide about the implementation here.

Custom cursor code override

Here's the code you need to copy and create a code override file in your project. Afterward, just apply that code override to your cursor frame to transform it into your custom cursor.

import type { ComponentType } from "react"
import { useRef, useState, useEffect } from "react"
import { motion, useSpring } from "framer-motion"

function hasButtonOrAnchorAncestor(element: HTMLElement | null): boolean {
    if (!element) {
        return false
    }

    if (element.tagName === "BUTTON" || element.tagName === "A") {
        return true
    }

    return hasButtonOrAnchorAncestor(element.parentElement)
}

export function withCursorFollow(Component: ComponentType): ComponentType {
    return (props: any) => {
        if (typeof document === "undefined") {
            return null as any
        }

        // Add a style tag to the head of the document to hide the system cursor for all elements
        const style = document.createElement("style")
        style.appendChild(
            document.createTextNode("* { cursor: none !important; }")
        )
        document.head.appendChild(style)

        const cursorRef = useRef(null)
        const [isHovering, setIsHovering] = useState(false)

        const spring = {
            type: "spring",
            stiffness: 1000,
            damping: 70,
        }

        const storedPosition = localStorage.getItem("cursorPosition")
        const initialCursorPosition = useRef(
            storedPosition
                ? JSON.parse(storedPosition)
                : { x: window.innerWidth / 2, y: window.innerHeight / 2 }
        )

        const positionX = useSpring(initialCursorPosition.current.x, spring)
        const positionY = useSpring(initialCursorPosition.current.y, spring)

        useEffect(() => {
            const handleMouseMove = (e: MouseEvent) => {
                if (!cursorRef.current) return

                // Check if the cursor is hovering a button or "A" tag element
                const isHovered =
                    e.target instanceof HTMLElement &&
                    (e.target.tagName === "BUTTON" ||
                        e.target.tagName === "A" ||
                        hasButtonOrAnchorAncestor(e.target.parentElement))
                setIsHovering(isHovered)

                // Update the position based on the cursor position
                positionX.set(e.clientX)
                positionY.set(e.clientY)

                localStorage.setItem(
                    "cursorPosition",
                    JSON.stringify({ x: e.clientX, y: e.clientY })
                )
            }

            // Store the initial cursor position when the component is first rendered
            initialCursorPosition.current.x = window.innerWidth / 2
            initialCursorPosition.current.y = window.innerHeight / 2

            window.addEventListener("mousemove", handleMouseMove)
            return () => {
                window.removeEventListener("mousemove", handleMouseMove)
            }
        }, [])

        return (
            <motion.div
                ref={cursorRef}
                style={{
                    position: "fixed",
                    left: positionX,
                    top: positionY,
                    pointerEvents: "none",
                    transform: "translate(-50%, -50%)",
                    transition: "transform 0.2s ease, opacity 0.2s ease",
                    zIndex: 9999,
                    opacity: isHovering ? 0.5 : 1, // Adjust opacity on hovering interactive elements
                    scale: isHovering ? 1.7 : 1, // Adjust scale on hovering interactive elements
                }}
            >
                <Component {...props} />
            </motion.div>
        )
    }
}
import type { ComponentType } from "react"
import { useRef, useState, useEffect } from "react"
import { motion, useSpring } from "framer-motion"

function hasButtonOrAnchorAncestor(element: HTMLElement | null): boolean {
    if (!element) {
        return false
    }

    if (element.tagName === "BUTTON" || element.tagName === "A") {
        return true
    }

    return hasButtonOrAnchorAncestor(element.parentElement)
}

export function withCursorFollow(Component: ComponentType): ComponentType {
    return (props: any) => {
        if (typeof document === "undefined") {
            return null as any
        }

        // Add a style tag to the head of the document to hide the system cursor for all elements
        const style = document.createElement("style")
        style.appendChild(
            document.createTextNode("* { cursor: none !important; }")
        )
        document.head.appendChild(style)

        const cursorRef = useRef(null)
        const [isHovering, setIsHovering] = useState(false)

        const spring = {
            type: "spring",
            stiffness: 1000,
            damping: 70,
        }

        const storedPosition = localStorage.getItem("cursorPosition")
        const initialCursorPosition = useRef(
            storedPosition
                ? JSON.parse(storedPosition)
                : { x: window.innerWidth / 2, y: window.innerHeight / 2 }
        )

        const positionX = useSpring(initialCursorPosition.current.x, spring)
        const positionY = useSpring(initialCursorPosition.current.y, spring)

        useEffect(() => {
            const handleMouseMove = (e: MouseEvent) => {
                if (!cursorRef.current) return

                // Check if the cursor is hovering a button or "A" tag element
                const isHovered =
                    e.target instanceof HTMLElement &&
                    (e.target.tagName === "BUTTON" ||
                        e.target.tagName === "A" ||
                        hasButtonOrAnchorAncestor(e.target.parentElement))
                setIsHovering(isHovered)

                // Update the position based on the cursor position
                positionX.set(e.clientX)
                positionY.set(e.clientY)

                localStorage.setItem(
                    "cursorPosition",
                    JSON.stringify({ x: e.clientX, y: e.clientY })
                )
            }

            // Store the initial cursor position when the component is first rendered
            initialCursorPosition.current.x = window.innerWidth / 2
            initialCursorPosition.current.y = window.innerHeight / 2

            window.addEventListener("mousemove", handleMouseMove)
            return () => {
                window.removeEventListener("mousemove", handleMouseMove)
            }
        }, [])

        return (
            <motion.div
                ref={cursorRef}
                style={{
                    position: "fixed",
                    left: positionX,
                    top: positionY,
                    pointerEvents: "none",
                    transform: "translate(-50%, -50%)",
                    transition: "transform 0.2s ease, opacity 0.2s ease",
                    zIndex: 9999,
                    opacity: isHovering ? 0.5 : 1, // Adjust opacity on hovering interactive elements
                    scale: isHovering ? 1.7 : 1, // Adjust scale on hovering interactive elements
                }}
            >
                <Component {...props} />
            </motion.div>
        )
    }
}
import type { ComponentType } from "react"
import { useRef, useState, useEffect } from "react"
import { motion, useSpring } from "framer-motion"

function hasButtonOrAnchorAncestor(element: HTMLElement | null): boolean {
    if (!element) {
        return false
    }

    if (element.tagName === "BUTTON" || element.tagName === "A") {
        return true
    }

    return hasButtonOrAnchorAncestor(element.parentElement)
}

export function withCursorFollow(Component: ComponentType): ComponentType {
    return (props: any) => {
        if (typeof document === "undefined") {
            return null as any
        }

        // Add a style tag to the head of the document to hide the system cursor for all elements
        const style = document.createElement("style")
        style.appendChild(
            document.createTextNode("* { cursor: none !important; }")
        )
        document.head.appendChild(style)

        const cursorRef = useRef(null)
        const [isHovering, setIsHovering] = useState(false)

        const spring = {
            type: "spring",
            stiffness: 1000,
            damping: 70,
        }

        const storedPosition = localStorage.getItem("cursorPosition")
        const initialCursorPosition = useRef(
            storedPosition
                ? JSON.parse(storedPosition)
                : { x: window.innerWidth / 2, y: window.innerHeight / 2 }
        )

        const positionX = useSpring(initialCursorPosition.current.x, spring)
        const positionY = useSpring(initialCursorPosition.current.y, spring)

        useEffect(() => {
            const handleMouseMove = (e: MouseEvent) => {
                if (!cursorRef.current) return

                // Check if the cursor is hovering a button or "A" tag element
                const isHovered =
                    e.target instanceof HTMLElement &&
                    (e.target.tagName === "BUTTON" ||
                        e.target.tagName === "A" ||
                        hasButtonOrAnchorAncestor(e.target.parentElement))
                setIsHovering(isHovered)

                // Update the position based on the cursor position
                positionX.set(e.clientX)
                positionY.set(e.clientY)

                localStorage.setItem(
                    "cursorPosition",
                    JSON.stringify({ x: e.clientX, y: e.clientY })
                )
            }

            // Store the initial cursor position when the component is first rendered
            initialCursorPosition.current.x = window.innerWidth / 2
            initialCursorPosition.current.y = window.innerHeight / 2

            window.addEventListener("mousemove", handleMouseMove)
            return () => {
                window.removeEventListener("mousemove", handleMouseMove)
            }
        }, [])

        return (
            <motion.div
                ref={cursorRef}
                style={{
                    position: "fixed",
                    left: positionX,
                    top: positionY,
                    pointerEvents: "none",
                    transform: "translate(-50%, -50%)",
                    transition: "transform 0.2s ease, opacity 0.2s ease",
                    zIndex: 9999,
                    opacity: isHovering ? 0.5 : 1, // Adjust opacity on hovering interactive elements
                    scale: isHovering ? 1.7 : 1, // Adjust scale on hovering interactive elements
                }}
            >
                <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