This tutorial will guide you through the process of creating an elastic custom cursor using vanilla JavaScript. This enhances user experience by providing a visually engaging and interactive cursor that responds dynamically to mouse movements, adding a unique touch to your web projects.
Setting Up the HTML Structure
First, we’ll establish the basic HTML structure needed for our custom cursor. This involves creating a simple div element that will represent our cursor.
<div class="circle"></div>
<script src="./script.js"></script>
Styling the Custom Cursor with CSS
Next, we’ll use CSS to style our custom cursor, defining its appearance and behavior. This includes setting its size, color, and position on the screen.
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
body {
min-height: 100lvh;
background-color: #050908;
}
.circle {
--circle-size: 40px;
position: fixed;
height: var(--circle-size);
width: var(--circle-size);
border: 1px solid white;
border-radius: 100%;
top: calc(var(--circle-size) / 2 * -1);
left: calc(var(--circle-size) / 2 * -1);
pointer-events: none;
}
Implementing the Elastic Behavior with JavaScript
Now, we’ll use JavaScript to create the elastic effect. This involves tracking the mouse position and dynamically updating the cursor’s position, scale, and rotation based on the mouse’s movement.
/**
* YouTube Tutorial:
* https://youtu.be/wG_5453Vq98
*/
console.clear();
// Select the circle element
const circleElement = document.querySelector('.circle');
// Create objects to track mouse position and custom cursor position
const mouse = { x: 0, y: 0 }; // Track current mouse position
const previousMouse = { x: 0, y: 0 } // Store the previous mouse position
const circle = { x: 0, y: 0 }; // Track the circle position
// Initialize variables to track scaling and rotation
let currentScale = 0; // Track current scale value
let currentAngle = 0; // Track current angle value
// Update mouse position on the 'mousemove' event
window.addEventListener('mousemove', (e) => {
mouse.x = e.x;
mouse.y = e.y;
});
// Smoothing factor for cursor movement speed (0 = smoother, 1 = instant)
const speed = 0.17;
// Start animation
const tick = () => {
// MOVE
// Calculate circle movement based on mouse position and smoothing
circle.x += (mouse.x - circle.x) * speed;
circle.y += (mouse.y - circle.y) * speed;
// Create a transformation string for cursor translation
const translateTransform = `translate(${circle.x}px, ${circle.y}px)`;
// SQUEEZE
// 1. Calculate the change in mouse position (deltaMouse)
const deltaMouseX = mouse.x - previousMouse.x;
const deltaMouseY = mouse.y - previousMouse.y;
// Update previous mouse position for the next frame
previousMouse.x = mouse.x;
previousMouse.y = mouse.y;
// 2. Calculate mouse velocity using Pythagorean theorem and adjust speed
const mouseVelocity = Math.min(Math.sqrt(deltaMouseX**2 + deltaMouseY**2) * 4, 150);
// 3. Convert mouse velocity to a value in the range [0, 0.5]
const scaleValue = (mouseVelocity / 150) * 0.5;
// 4. Smoothly update the current scale
currentScale += (scaleValue - currentScale) * speed;
// 5. Create a transformation string for scaling
const scaleTransform = `scale(${1 + currentScale}, ${1 - currentScale})`;
// ROTATE
// 1. Calculate the angle using the atan2 function
const angle = Math.atan2(deltaMouseY, deltaMouseX) * 180 / Math.PI;
// 2. Check for a threshold to reduce shakiness at low mouse velocity
if (mouseVelocity > 20) {
currentAngle = angle;
}
// 3. Create a transformation string for rotation
const rotateTransform = `rotate(${currentAngle}deg)`;
// Apply all transformations to the circle element in a specific order: translate -> rotate -> scale
circleElement.style.transform = `${translateTransform} ${rotateTransform} ${scaleTransform}`;
// Request the next frame to continue the animation
window.requestAnimationFrame(tick);
}
// Start the animation loop
tick();
That’s all! You’ve successfully created an elastic custom cursor using vanilla JavaScript. This effect can significantly enhance the user experience of your website by providing interactive feedback to user actions.







