Change the size of a custom cursor on click using React

I have customized the cursor on my react app, but I want to make it animate when the user clicks. Perhaps by decreasing its size or some other effect. The cursor is within a component that I've included in my Index.js file. I am unsure how to create an event listener that changes the cursor's class. As a newcomer to web development, any assistance would be greatly appreciated :)

Below is the Custom Cursor component :

import React, { useRef } from 'react'

function CustomCursor() {

const cursorRef = useRef(null)

React.useEffect(() => {
    document.addEventListener('mousemove', (event)=>  {
        const {clientX, clientY} = event;
        const mouseX = clientX - cursorRef.current.clientWidth /2;
        const mouseY = clientY - cursorRef.current.clientHeight /2;
        cursorRef.current.style.transform = `translate3d(${mouseX}px, ${mouseY}px, 0)`
    })
}, [])

    return ( <div className='custom-cursor' ref={cursorRef}></div> ) }

export default CustomCursor 

The CSS class details are as follows :

.custom-cursor {
  z-index: 9999;
  border-radius: 50%;
  width: 20px;
  height: 20px;
  background-color: #8c8c8cb8;
  pointer-events: none;
  overflow: hidden;
  transform: translate(-50%, -50%);
  position: fixed;
}

I'm feeling a bit lost on what steps to take next :/

Answer №1

To implement this feature, you can attach a click event listener to the document or window object and modify the cursor style by applying a CSS class or directly manipulating the HTML element's JS style property. Later on, revert these changes after a specified duration.

Creating a Custom Cursor Style on Click -

.custom-cursor.clicked {
  width: 10px;
  height: 10px;
}

Click Event Listener Implementation -

const handleCursorClick = () => {
    // Update cursor styles
    cursorRef.current.classList.add("clicked");

    // Alternatively, apply changes directly via JavaScript like so
    // cursor.current.style.width = '15px'
    // cursor.current.style.height = '15px'

    setTimeout(() => {
      // Revert changes after a set time
      cursorRef.current.classList.remove("clicked");

      // cursor.style.width = '20px'  <-- default style
      // cursor.style.height = '20px' <-- default style
    }, 100);
  };

Answer №2

If you want to add animation to the UI, you can achieve it by attaching an event listener to either the window object or the custom cursor itself.

Below is a sample code snippet that demonstrates this:

function CustomCursor() {
  const [isClicked, setClicked] = useState(false);
  const cursorRef = useRef(null);

  React.useEffect(() => {
    let timer;

    const mouseX = (event) => event.clientX;
    const mouseY = (event) => event.clientY;

    const positionElement = (event) => {
      const mouse = {
        x: mouseX(event),
        y: mouseY(event)
      };
      cursorRef.current.style.top = mouse.y + "px";
      cursorRef.current.style.left = mouse.x + "px";
    };
    
    const onMove = (event) => {
      timer = setTimeout(positionElement(event), 1);
    };

    window.addEventListener("mousemove", onMove);

    return () => {
      clearInterval(timer);
    };
  }, []);

  const onClick = (e) => {
    e.preventDefault();
    setClicked((pre) => !pre);
  };

  const clickedClass = isClicked ? "-clicked" : "";

  return (
    <div
      onClick={onClick}
      className={`custom-cursor${clickedClass}`}
      ref={cursorRef}
    ></div>
  );
}

export default CustomCursor;

To see this in action, check out this live example on CodeSandbox

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Excessive text in HTML div element

Whenever I maximize the window in any browser, I type a long string in a div or span tag. It perfectly fits within the div tag. However, when I minimize or compress the browser width, the text spills out of the div area. I am looking for a solution to set ...

What could be causing my CSS relative positioning to malfunction?

I am struggling to adjust the positioning of my divs using relative and absolute properties. Any advice on how to resolve this issue would be greatly appreciated. Thank you. Example Code: <div id="game"><img src="gta-game.jpg" height="100" width ...

What is the best way to implement a personalized hook in React that will return the number of times a specific key is pressed?

I'm working on a custom hook that should give me the key pressed, but I've noticed that when I press the same key more than twice, it only registers twice. Here's my code: import { useEffect, useState } from "react" function useKe ...

The Fetch API within DatoCMS isn't able to retrieve all published posts

I am trying to retrieve all of my published blog posts from DatoCMS. Currently, I have implemented the code below. The issue I am facing is that it only retrieves 65 posts when I know I have more than 100... Can anyone help me figure out what I might be d ...

Something seems off with Chrome

I am facing a unique issue that I need help with. Unfortunately, the code is too long to post here but essentially it involves creating a menu for a website. The menu works perfectly and looks great on all browsers except for Chrome. This is unusual as Ch ...

Tips for updating the hover effect color on Material UI select component options in a React JS application

I've been trying to customize the hover effect for the options in the mui Auto Complete component drop-down menu, but I'm having trouble finding the right method to do so. Here is the hover effect that I want to change: Image I'd like to u ...

Enhancing OpenSeadragon images with custom overlays and managing error messages

Currently, I am experimenting with the Basic Single-Row Tile Source Collection example using the same configurations and tile sources outlined in the example. However, I am encountering difficulties in adding overlays to the first and second images as int ...

Tips for organizing a grid to achieve the desired layout

Overview I am working on organizing items within the MUI Grid. The grid consists of multiple dynamic rows and columns. Each row has a fixed first column, followed by a variable number of scrollable columns. The scrollable columns should be grouped togethe ...

What is the best way to clear radio button selections in a form using reactjs?

I designed a survey form with 4 radio buttons for a single question. I also included buttons to submit the form and clear input fields. However, when I click on "Clear Input," the checked radio buttons do not get cleared. How can I achieve this using the r ...

Ways to adjust the div height to match the span height

.headerDesc { width: 100% + 1px; height: 70px; background-color: #4d2765; margin: 0 -8px; } .headerDesc span { padding: 5px; position: absolute; color: white; font-family: 'Arial', sans-serif; text-al ...

Error message: Unable to locate elementError: Selenium VBA

I am encountering an error in SeleniumVBA when trying to upload a file on an internal website. Can someone please assist me in resolving this issue? I am attempting to log in to a website and upload a file from a source to download some data. However, whe ...

Is it possible to modify the spacing of menu items in the React Material-ui Drawer component?

Recently, I decided to incorporate Material-UI into a React project for the first time. The AppBar was set up to trigger Drawer, which displayed a list of menu items in the sidebar. However, an issue arose with excessive margin-top spacing. Here is an ill ...

Custom time selector does not automatically set the default value

After creating two inputs where one represents hours and the other minutes, clicking on edit should display the total time in seconds. The original time for editing should remain unchanged until you choose to save it. Here is the link to the code: https:// ...

Adaptable HTML design with alignment features

Here is the structure I am working with: <style> #main { max-width: 500px; margin: 0 auto; overflow: hidden; border: 1px solid red; } #container{ margin-right: -50px; } .block{ display: inline-block; width: 100px; height: 100px; border: 1px solid gr ...

Tips for Customizing Dialogs with CSS Classes in mui5 Using Emotion/Styled

When attempting to customize the styling of a mui Dialog, I encountered an issue where it wouldn't accept className even when placed inside PaperProps. While inline styles worked, my preference was to import styles from a separate stylesheet named Sty ...

Create a script that will split a single block of text into separate sections based on predefined conditions

I have developed a script using Tampermonkey which modifies a value on a specific webpage. On the webpage, there is an input box with the value "FPPUTHP1100000". This value is a material code with the following structure: F represents FRESH PPUTHP repr ...

Stop the page from scrolling

I'm trying to find a way to disable page scrolling, so I used this style for the body: overflow: hidden; Surprisingly, it worked perfectly on desktop but had no effect on mobile devices. After checking out this resource, it seems that creating a ch ...

The React component was not able to receive any children as input

My Typescript-written React component is called GradientText.tsx: import React, { ReactNode } from "react" import { cn } from "@/lib/utils" const typeMap = { h1: "h1", h2: "h2", p: "p", } inte ...

Achieving text-overflow: ellipsis functionality with mandatory content following

I have a list containing text and corresponding counts, displayed as follows: +----------------------------+ | Text A (123) | | Some other text (456,789) | +----------------------------+ Due to space limitations in my UI, I need to ensure ...

Encountering an issue when attempting to send a post request with an image, resulting in the following error: "Request failed with status code

Whenever I submit a post request without including an image, everything goes smoothly. However, when I try to add an image, the process fails with an Error: Request failed with status code 409. Below is the code snippet for my react form page. const Entry ...