Docs
Arrow Cursor Effect
An interactive React component that adds a dynamic bubble effect, visually tracking cursor movement in real time.
Installation
Install dependencies
npm install framer-motion lucide-react
Run the following command
It will create a new file arrow-cursor-effect.tsx
inside the components/mage-ui/cursor-effects
directory.
mkdir -p components/mage-ui/cursor-effects && touch components/mage-ui/cursor-effects/arrow-cursor-effect.tsx
Paste the code
Open the newly created file and paste the following code:
'use client';
import React, { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
const ArrowCursor: React.FC = () => {
const [lastY, setLastY] = useState<number | null>(null);
const [direction, setDirection] = useState<'up' | 'down' | null>(null);
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
// Track mouse position
setMousePosition({ x: e.clientX, y: e.clientY });
// Determine direction
if (lastY !== null) {
if (e.clientY < lastY) {
setDirection('up');
} else if (e.clientY > lastY) {
setDirection('down');
}
}
setLastY(e.clientY);
};
window.addEventListener('mousemove', handleMouseMove);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
};
}, [lastY]);
// Add another useEffect to set the height dynamically
useEffect(() => {
const setHeight = () => {
const vh = window.innerHeight;
document.documentElement.style.setProperty('--vh', `${vh}px`);
};
setHeight();
window.addEventListener('resize', setHeight);
return () => window.removeEventListener('resize', setHeight);
}, []);
const arrowVariants = {
initial: {
opacity: 0,
scale: 0.5,
rotate: direction === 'up' ? 0 : 180,
},
animate: {
opacity: 1,
scale: 1,
rotate: direction === 'up' ? 0 : 180,
},
exit: {
opacity: 0,
scale: 0.5,
},
};
return (
<div
className=' top-0 left-0 w-full h-screen pointer-events-none z-50'
style={{ height: 'var(--vh, 100vh)' }}
>
<AnimatePresence>
{direction && (
<motion.div
key={`${direction}-arrow`}
style={{
position: 'fixed',
top: mousePosition.y - 25,
left: mousePosition.x + 15, // Offset 15 pixels to the right
}}
initial='initial'
animate='animate'
exit='exit'
variants={arrowVariants}
>
<div className='w-[50px] h-[50px] bg-black dark:bg-white rounded-full flex items-center justify-center'>
<svg
xmlns='http://www.w3.org/2000/svg'
width='30'
height='30'
viewBox='0 0 24 24'
fill='none'
stroke='currentColor'
strokeWidth='2'
strokeLinecap='round'
strokeLinejoin='round'
className='text-white dark:text-black'
>
<line x1='12' y1='19' x2='12' y2='5'></line>
<polyline points='5 12 12 5 19 12'></polyline>
</svg>
</div>
</motion.div>
)}
</AnimatePresence>
</div>
);
};
export default ArrowCursor;