Incorporating timed hover effects in React applications

Take a look at the codesandbox example

I'm currently working on implementing a modal that appears after a delay when hovering over a specific div. However, I've encountered some challenges. For instance, if the timeout is set to 1000ms and you hover over the div but move away before the 1000ms mark, the modal still pops up. What I really want is for the modal to only appear after the full delay period if the mouse stays over the div. How can I achieve this desired effect without the unintended consequences I'm facing now? Any suggestions are appreciated!

index.tsx:

import * as React from "react";
import ReactDOM from "react-dom";
import "./styles.css";

const Modal: React.FC = () => {
  const divRef = React.useRef<HTMLDivElement>(null);
  const [showModal, setShowModal] = React.useState<boolean>(false);

  React.useEffect(() => {
    const divNode = divRef.current;

    const handleEvent = (event: Event): void => {
      if (divNode) {
        if (divNode.contains(event.target as Node)) {
          setTimeout(() => setShowModal(true), 1000);
        } else {
          setShowModal(false);
        }
      }
    };

    document.addEventListener("mouseover", handleEvent);

    return () => {
      document.removeEventListener("mouseover", handleEvent);
    };
  }, [divRef]);

  return (
    <div className="container">
      <div className="div" ref={divRef}>
        Hover Over Me
      </div>
      {showModal && <div className="modal">This is the modal</div>}
    </div>
  );
};

const App: React.FC = () => (
  <>
    <Modal />
    <Modal />
    <Modal />
    <Modal />
  </>
);

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Answer №1

A mouse out event needs to be included in order to hide the modal.

By calling a function on the 'mouseout' event listener and setting showModal to false, the modal will be hidden whenever the mouse is moved.

setShowModal(false)

Additionally, consider setting a timeout to a variable and using clearTimeout(variable_that_set_to_timeout) on mouseout event:

 React.useEffect(() => {
    const divNode = divRef.current;
    let timeout = null;

    const handleEvent = (event: Event): void => {
      if (divNode) {
        if (divNode.contains(event.target as Node)) {
          timeout = setTimeout(() => setShowModal(true), 1000);
        } else {
          setShowModal(false);
        }
      }
    };

    const hideModal = (event: Event): void => {
      clearTimeout(timeout);
      setShowModal(false);
    };

    divNode.addEventListener("mouseover", handleEvent);

    divNode.addEventListener("mouseout", hideModal);

    return () => {
      document.removeEventListener("mouseover", handleEvent);
    };
  }, [divRef]);

Visit this sandbox link for more details.

Answer №2

It's advisable to refrain from manipulating the DOM directly in React as it differs from jQuery. Here is an alternative approach for creating a modal component:

const Modal: React.FC = () => {
  const [timeout, setModalTimeout] = React.useState(null);
  const [showModal, setShowModal] = React.useState<boolean>(false);
  return (
    <div className="container">
      <div className="div" onMouseEnter={() => {
         timeout && !showModal && clearTimeout(timeout);
         setModalTimeout(setTimeout(() => setShowModal(true), 1000))
      }} onMouseLeave={() => {
        timeout && clearTimeout(timeout)
        setShowModal(false);
      }}>
        Hover Me
      </div>
      {showModal && <div className="modal">modal</div>}
    </div>
  );
};

References:

Answer №3

To handle this situation effectively, it is recommended to develop a custom useTimeout hook and oversee the state of the hover action.

import { useState } from "react";
import useTimeout from "./useTimeout";

export default function App() {
  const [visible, setVisible] = useState(false);
  const [hovered, setHovered] = useState(false);

  //close after 3s
  useTimeout(() => setVisible(true), !visible && hovered ? 3000 : null);

  return (
    <div className="App">
      <h1>Hover Timeout Example</h1>
      <div
        onMouseEnter={() => setHovered(true)}
        onMouseLeave={() => setHovered(false)}
      >
        Hover me for 3s to show modal
        <div>Hover status: {hovered ? "true" : "false"}</div>
      </div>
      
      {visible && (
        <div>
          <h1>Modal</h1>
          <div>
            <button onClick={() => setVisible(false)}>close</button>
          </div>
        </div>
      )}
    </div>
  );
}

Code Sandbox

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

Display a dynamic variable within React's HTML code

const fetchTime = () => { const currentDate = new Date(); const currentTime = currentDate + ' ' + currentDate.getHours() + ":" + currentDate.getMinutes() + ":" + currentDate.getSeconds(); return {currentTime}; } export default fun ...

Iterating through a dataset in JavaScript

Trying to find specific information on this particular problem has proven challenging, so I figured I would seek assistance here instead. I have a desire to create an arc between an origin and destination based on given longitude and latitude coordinates. ...

There seems to be an issue as the function reporter.beforeLaunch cannot be identified and

I am currently attempting to incorporate the protractor screenshot reporter for jasmine 2. However, I encountered the following error in the terminal: /usr/local/bin/node lib/cli.js example/conf.js /Users/sadiq/node_modules/protractor/node_modules/q/q.j ...

Creating and accessing a temporary binary file using Node Js

Challenge I have been working on integrating the Google Text To Speech (TTS) service to save a generated binary audio file to Google Cloud Storage (GCS). Considering that saving a local binary file in Firebase's Cloud Functions environment may not b ...

Interacting with a third-party application via OAuth using Node server to send REST requests

https://i.stack.imgur.com/Znrp0.png I've been working on a server to manage chat messages and need to integrate with a JIRA instance. I'm currently using the passport-atlassian-oauth strategy for authentication and BearerStrategy for requests. H ...

Discover an Effective Approach for Transmitting Form-Data as a JSON Object

Hey there! I'm encountering a bit of an issue with sending some data as a JSON object. The problem arises when trying to send images using FormData. It seems like I need to convert my form data into a single JSON object. Can anyone assist me with this ...

The error message indicates that the 'aboutData' property is not found within the 'never[]' data type

What is the correct method for printing array elements without encountering the error message "Property 'post_title' does not exist on type 'never[]'?" How can interfaces be used to define variables and utilize them in code for both ab ...

Error: Unable to locate npm package

I am currently working on an Angular application that was created using Grunt and relies on Bower and NPM. Recently, I attempted to install an npm module locally. The installation resulted in the files being stored in the main application directory under ...

Choosing an automatically generated choice from a C# web browser control

Using a c# web browser control, I am navigating a commercial website to access a list of potential jobs. However, I encountered an issue while trying to bid on these jobs through some links. The problem arises when dealing with forms that contain two sele ...

Adjust the baseline of the text within the <li> element by moving it 2 pixels upwards

My webpage menu is set up with inline lis within a ul. Each li has a colored border and contains an a element. I want to change the color of the text inside the a element and move it 2 pixels up when hovering over it without affecting the li border. How ...

Is there a way in JavaScript to launch a link in a new tab and overlay a div on top of the existing content of the page?

Is there any method in JavaScript to open a link in a new tab and add a div element on that page? Let's say I have a page called page1.html which has a div containing a link and two radio buttons "yes" and "no". I want to open the link in a separate t ...

Is there a way to attach a model to an Angular directive?

Currently, I am implementing angular's typeahead functionality using the following resource: I have created a directive with the following template: <div> <input type="text" ng-model="user.selected" placeholder="Ty ...

List output with jQuery AJAX showing object data

Here is my code that utilizes ajax for searching: $("#keyword").keyup(function() { var keyword = $("#keyword").val(); if (keyword.length >= MIN_LENGTH) { $.get( "./lib/data_siswa_ajax.php", { keyword: keyword, sekolah: $("#sekolah").val ...

React Material-UI - implementing custom colors in Alert component leads to error: "Cannot read properties of undefined (reading 'type')"

I've been working on customizing MUI components to match our company's design, but I've hit a roadblock. While defining my custom colors, I noticed that instead of "error" we have a color called "danger." I followed the guidelines in the do ...

How can I change the displayed value of a 'select' element programmatically in Internet Explorer?

My interactive graphic has a drop-down menu implemented with a <select> element. Everything functions correctly, except when using Internet Explorer. The issue arises when attempting to programmatically change the selected value of the <select> ...

What could be the reason for `process.env.myvariable` not functioning in a Next.js project with TypeScript

After creating a file called .env.local in the root directory of my project, I added a variable called WEBSOCKET_VARIABLE=THIS_IS_TEXT to it. However, when I try to access it using process.env.WEBSOCKET_VARIABLE, nothing is found. What could be causing ...

After triggering an action, I am eager to make a selection from the store

To accomplish my task, I must first select from the store and verify if there is no data available. If no data is found, I need to dispatch an action and then re-select from the store once again. Here is the code snippet that I am currently using: t ...

What is the best way to add a 'Drawer' component into the 'AppBar' using React MUI within the Next.js framework?

My goal is to create an App bar with a 'hamburger' icon on the left that, when clicked, will display a Sidenav (drawer). I am working with React Material and Next.js (App router) and need to have the app bar and drawer as separate components, hea ...

React Native error - "Invalid element type: expected a string or class/function, but received undefined" - encountering issue with importing a custom library?

Alright, I'm looking to make some modifications to this library, so I am attempting to import the non-transpiled version by downloading the repository and importing it from here: https://github.com/nicotroia/react-native-floating-action-menu#readme A ...

Displaying various Ajax html responses

The function $('.my-button').click(function(e) is designed to display the output of the MySQL query in display.php, presented in HTML format. While it functions correctly, since each button is looped for every post, the script only works for the ...