Docs
Custom Pointer
Custom Pointer
Cursor changes on hover to card and moves with a name tag with random color each time.
Hover Me
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Recusandae qui illo consequatur delectus repellat dignissimos soluta incidunt! Iste ab animi nes

Ankush
Install the following dependencies:
pnpm add gsap
Make a file for cn function and match the import afterwards
import clsx, { ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export const cn = (...classes: ClassValue[]) => twMerge(clsx(...classes))
Make a file and copy paste this code in a file with name CustomCursor
"use client"
import * as React from "react"
import gsap from "gsap"
import { cn } from "@/lib/utils"
import { useGSAP } from "@gsap/react"
const colorPairs = [
{ primary: "#FF6B6B", secondary: "#4ECDC4" },
{ primary: "#A17FB0", secondary: "#5D5FEF" },
{ primary: "#FF9F43", secondary: "#FF5E7D" },
{ primary: "#00D2FF", secondary: "#3A7BD5" },
{ primary: "#08AEEA", secondary: "#2AF598" },
]
const getRandomColorPair = () => {
return colorPairs[Math.floor(Math.random() * colorPairs.length)]
}
interface CursorIconProps extends React.HTMLAttributes<HTMLDivElement> {}
const CursorIcon = ({ className, children, ...props }: CursorIconProps) => (
<div className={cn("mb-4", className)} {...props}>
{children}
</div>
)
interface NameTagProps extends React.HTMLAttributes<HTMLDivElement> {
name?: string
src?: string
}
function NameTag({ name, src, className, children, ...props }: NameTagProps) {
if (name || src) {
return (
<div
className={cn(
"flex items-center p-2 rounded-2xl gap-3 mt-4 scale-0",
className
)}
{...props}
>
{src && (
<img
src={src}
className="h-5 w-5 border rounded-full"
alt="Profile"
/>
)}
{name && <p className="font-semibold">{name}</p>}
</div>
)
}
return <div {...props}>{children}</div>
}
interface CustomCursorProps extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode
}
const CustomCursor = ({ children, className, ...props }: CustomCursorProps) => {
const [colors, setColors] = React.useState(getRandomColorPair)
const [hasCursorIcon, setHasCursorIcon] = React.useState(false)
const localRef = React.useRef<HTMLDivElement>(null)
useGSAP(() => {
const prefersDark = window.matchMedia(
"(prefers-color-scheme: dark)"
).matches
let parent = localRef.current?.parentElement
if (!parent || !localRef.current) return
const mouseEnter = () => {
gsap.to(localRef.current, { opacity: 1, duration: 0.1 })
gsap.to("[data-nametag]", { scale: 1, duration: 0.3 })
parent.style.border = `1px solid ${colors.secondary}`
}
const mouseLeave = () => {
gsap.to(localRef.current, { opacity: 0, duration: 0.1 })
gsap.to("[data-nametag]", { scale: 0, duration: 0.1 })
setColors(getRandomColorPair())
parent.style.border = `0.5px solid ${prefersDark ? "#E9E9E8" : "#262626"}`
// parent.classList.add("border");
}
const mouseMove = (e: MouseEvent) => {
const rect = parent.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
gsap.to(localRef.current, { x, y, duration: 0.1 })
}
parent.addEventListener("mouseenter", mouseEnter)
parent.addEventListener("mouseleave", mouseLeave)
parent.addEventListener("mousemove", mouseMove)
return () => {
parent.removeEventListener("mouseenter", mouseEnter)
parent.removeEventListener("mouseleave", mouseLeave)
parent.removeEventListener("mousemove", mouseMove)
parent.style.cursor = ""
}
}, [colors])
// Improved detection of CursorIcon component
React.useEffect(() => {
// Initialize with false
let foundCursorIcon = false
// Enhanced check for CursorIcon components
React.Children.forEach(children, (child) => {
if (child && React.isValidElement(child)) {
// Check if the component is CursorIcon
if (
(child.type as any).name === "CursorIcon" ||
(child.type as any).displayName === "CursorIcon" ||
(child.type as any)._payload?.value?.displayName == "CursorIcon"
) {
foundCursorIcon = true
}
}
})
setHasCursorIcon(foundCursorIcon)
}, [children])
return (
<div
ref={localRef}
className={cn(
"absolute top-0 left-0 opacity-0 pointer-events-none",
className
)}
{...props}
>
{/* Only show default cursor when no CursorIcon is found */}
{!hasCursorIcon && (
<CursorIcon style={{ color: colors.secondary }}>
<svg
style={{ rotate: "-70deg" }}
className="scale-150"
stroke="currentColor"
fill="currentColor"
strokeWidth="0"
viewBox="0 0 16 16"
height="20px"
width="20px"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M14.082 2.182a.5.5 0 0 1 .103.557L8.528 15.467a.5.5 0 0 1-.917-.007L5.57 10.694.803 8.652a.5.5 0 0 1-.006-.916l12.728-5.657a.5.5 0 0 1 .556.103z"></path>
</svg>
</CursorIcon>
)}
{children &&
React.Children.map(children, (child) =>
React.isValidElement(child)
? React.cloneElement(child, {
// @ts-ignore
style: {
backgroundColor:
(child.type as any).displayName !== "CursorIcon"
? colors.secondary
: undefined,
} as React.CSSProperties,
"data-nametag": true,
})
: child
)}
</div>
)
}
// Add displayName for better component identification
CursorIcon.displayName = "CursorIcon"
NameTag.displayName = "NameTag"
export { CustomCursor, CursorIcon, NameTag }
Usage
Custom Pointer With Custom Cursor
Hover Me
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Recusandae qui illo consequatur delectus repellat dignissimos soluta incidunt! Iste ab animi nes

Ankush