In this article, I will guide you through the process of creating a custom cursor for your React application using Framer motion. At the end of the tutorial, you will have built a custom cursor that looks like the following:
Prerequisite
To follow along with this tutorial, you’ll need the following:
- A text editor
- Node.js installed locally on your machine
- Working knowledge of HTML, CSS, and JavaScript
- Working knowledge of React
You can find the complete code for this tutorial at this CodeSandbox.
Let’s get started!
Setting up the Project
Now, let’s set up a simple React project and install the necessary dependencies.
We’ll start by installing React:
npx create-react-app custom-cursor-app
Or you can use Yarn
yarn create react-app custom-cursor-app
Next, we’ll install Framer Motion
npm install framer-motion
Or you can use Yarn
yarn add framer-motion
Getting Started
First, we'll open the App.js file and remove some of the code in it, next we'll replace it with these few lines of code
import "./App.css";
const App = () => {
return (
<div className="App">
<h1 className="title">Custom Cursor</h1>
<div className="cursor"></div>
</div>
);
};
export default App;
Next, we’ll import everything else that’s required to help us create a custom cursor, from the libraries we installed earlier:
useState
and useEffect
Hooks from React.
motion
Hook from Framer Motion.
import { useState, useEffect } from "react";
import { motion } from "framer-motion";
Next, open the App.css file and remove the code in it and place these lines of code in the file, this helps us style the App.js file
@import url("https://fonts.googleapis.com/css2?family=Mochiy+Pop+One&display=swap");
*,
*::before,
*::after {
margin: 0;
padding: 0;
}
.App {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
background-color: aqua;
font-family: "Mochiy Pop One", sans-serif;
}
.title {
font-size: 5rem;
}
.cursor {
background-color: #111;
height: 16px;
width: 16px;
border-radius: 50%;
position: fixed;
top: 0;
left: 0;
pointer-events: none;
}
Getting the Mouse position
To get the mouse position when running the app, we'll need the useState and useEffect Hooks provided by React.
import "./App.css";
import { useState, useEffect } from "react";
import { motion } from "framer-motion";
const App = () => {
// state for mouse position
const [mousePosition, setMousePosition] = useState({
x: 0,
y: 0,
});
useEffect(() => {
const mouseMove = (e) => {
setMousePosition({
x: e.clientX,
y: e.clientY,
});
};
window.addEventListener("mousemove", mouseMove);
return () => {
window.removeEventListener("mousemove", mouseMove);
};
}, []);
return (
<div className="App">
<h1 className="title">Custom Cursor</h1>
<div className="cursor"></div>
</div>
);
};
export default App;
Here, we use the useState
Hook to set the state for the mouse position.
In the useEffect
Hook, we are getting the current position of the mouse using the window
object.
Next, we set the state x and y of the mousePosition
using the clientX
and clientY
method from the event object.
We are now able to track the movement of the mouse on the screen.
Adding Animations
Next up, we'll be animating the mouse cursor using the motion module we imported from Framer motion.
const App = () => {
// Variant animation
const variants = {
default: {
x: mousePosition.x - 8,
y: mousePosition.y - 8,
},
};
return (
<div className="App">
<h1 className="title">
Custom Cursor
</h1>
// using the motion module to animate the cursor div element
<motion.div
className="cursor"
variants={variants}
animate="default"
></motion.div>
</div>
);
};
export default App;
Here, we are targetting the cursor element, we create a variant for the cursor animation, and set the default x
and y
position of the cursor element using the mousePosition
state, mousePosition.x
for the cursor element x
initial position and mousePosition.y
for the cursor element y
initial position.
In the App.css
file the cursor div element is styled to have a width and height of 16px
each, reducing the mousePosition.x
and mousePosition.y
by 8 helps center the mouse cursor in the cursor div element.
Next up, to remove the native browser cursor, in the App.css file paste this line of code.
*,
*::before,
*::after {
cursor: none;
}
Setting the Mixblendmode
To set the mixBlendMode for the custom cursor, open up the App.js file and edit the code.
// Set cursor variant to change color on hover text
const [cursorVariant, setCursorVariant] = useState("default");
// Variant animation
const variants = {
// default animation (applies onMouseLeave)
default: {
x: mousePosition.x - 8,
y: mousePosition.y - 8,
},
// text animation (applies onMouseEnter)
text: {
height: 150,
width: 150,
x: mousePosition.x - 70,
y: mousePosition.y - 70,
backgroundColor: "aqua",
mixBlendMode: "difference",
},
};
// function for textLeave and textEnter
const textEnter = () => setCursorVariant("text");
const textLeave = () => setCursorVariant("default");
return (
<div className="App">
<h1 className="title" onMouseEnter={textEnter} onMouseLeave={textLeave}>
Custom Cursor
</h1>
<motion.div
className="cursor"
variants={variants}
animate={cursorVariant}
></motion.div>
</div>
);
};
First, we create a new state for the cursor animation variant using the useState
Hook.
Next, we create a function to set the variant animation of the cursor element to text
animation when the mouse hovers over the h1 element, and we have another function to set the variant animation of the cursor element to default
when the mouse leaves the h1 element.
Going over the text variant animation, we set the width and height of the cursor element to 150px
each, and reduce the mousePosition
x
and y
by 70px each to center the cursor.
Next up we give the cursor element a background color of aqua
, so when the mouse enters the h1
element the color changes to aqua
.
Finally, we set the mixBlendMode
property to difference
.
The mixBlendMode property is what inverts the color of the h1
text to the aqua
color onMouseEnter.
Your complete custom cursor webpage should look like this:
You can find the complete code for this tutorial at this CodeSandbox.
Conclusion
Framer motion is an extremely helpful library to use when you want to create animations. You can find a full list of Framer-motion utilities in the animation section of the documentation.
Thanks for reading, and have fun playing around with this and make some tweaks to get a better custom cursor for your webpage!
If you enjoyed reading this as much as I enjoyed writing it, then Like and Share this with your friends and feel free to connect with me on Twitter 👨💻.