1

Javascript enables user interactions to be simulated.

Any script can simulate a user interaction like click or focus on a specific element on the page, by using the methods .click() and .focus().

Example:

const square = document.getElementsByClassName('square')[0];

const clickSquare = () => {

  event.target.dataset.receivedAction = 'click';
  event.target.innerHTML = '<p>I\'ve been clicked!</p>';
}

const clearSquare = () => {

  square.removeAttribute('data-received-action');
  square.innerHTML = '';
}

square.addEventListener('click', clickSquare, false);

const clickButton = document.querySelector('[data-deliver-action="click"]');
const clearButton = document.querySelector('[data-deliver-action="clear"]');

clickButton.addEventListener('click', () => square.click(), false);
clearButton.addEventListener('click', clearSquare, false);
.square {
display: block;
width: 120px;
height: 120px;
margin: 12px 6px;
text-align: center;
font-family: arial, helvetica, sans-serif;
font-weight: bold;
font-size: 14px;
text-transform: uppercase;
overflow: hidden;
cursor: pointer;
}

button {
display: block;
width: 160px;
margin: 6px;
cursor: pointer;
}

.square {
color: rgb(255, 0, 0);
background-color: rgb(255, 0, 0);
}

.square[data-received-action="click"] {
background-color: rgb(255, 255, 0);
}
<div class="square" tabindex="0"></div>

<button type="button" data-deliver-action="click">Click the Square</button>
<button type="button" data-deliver-action="clear">Clear Square</button>

The square above listens for a click event. We can either click on the square directly or we can press the Click the Square button which then clicks on the square itself via the .click() method.

Either action results in the square receiving a click event.

But this is only possible because the .click() method exists.

A .hover() (or even .mouseover()) method would also be useful, but it doesn't exist.

Is it possible to computationally simulate a hover (or a mouseover) in the absence of these methods?

Rounin
  • 27,134
  • 9
  • 83
  • 108
  • Possible duplicate of: [Pure JavaScript replacement for :hover](https://stackoverflow.com/questions/31629021/pure-javascript-replacement-for-hover) – Dexygen Nov 02 '19 at 21:22
  • 1
    @GeorgeJempty That has nothing to do with what is being asked here. – Scott Marcus Nov 02 '19 at 21:23
  • Trust me then, there's a duplicate out there somewhere, at least I'm effing looking for one – Dexygen Nov 02 '19 at 21:24
  • 1
    @GeorgeJempty How about the awesome answer below? – Scott Marcus Nov 02 '19 at 21:25
  • 1
    You can of course fire event `mouseover` listeners using `dispatchEvent`, but it's not possible to simulate a real, user-induced hover. – Bergi Nov 02 '19 at 21:26
  • 1
    The question above is not a duplicate of the question referenced in the duplicate notice. The latter question is concerned with CSS pseudo-class `:hover` - this question is concerned with computationally simulating human user interaction. – Rounin Nov 02 '19 at 22:42

1 Answers1

6

This appears not to be widely documented across the web, but it is possible to computationally simulate a human moving a mouse pointer over an element in the same way that element.click() simulates a human clicking on an element.

The correct approach is to use:

eventTarget.dispatchEvent(event)

in combination with a JS-native event.

Most references to dispatchEvent() involve a custom-written event, but, to reiterate, it is possible to use a JS-native event - in this case mouseover.

So... instead of the following, utilising the .click() method:

clickButton.addEventListener('click', () => square.click(), false);

We can deploy:

clickButton.addEventListener('click', () => {

  let hover = new Event('mouseover');
  square.dispatchEvent(hover);

}, false);

Working Example:

const square = document.getElementsByClassName('square')[0];

const clickSquare = () => {

  event.target.dataset.receivedAction = 'click';
  event.target.innerHTML = '<p>I\'ve been clicked!</p>';
}

const hoverSquare = () => {

  event.target.dataset.receivedAction = 'hover';
  event.target.innerHTML = '<p>I\'ve been hovered over!</p>';
}

const clearSquare = () => {

  square.removeAttribute('data-received-action');
  square.innerHTML = '';
}

square.addEventListener('mouseover', hoverSquare, false);
square.addEventListener('click', clickSquare, false);

const clickButton = document.querySelector('[data-deliver-action="click"]');
const hoverButton = document.querySelector('[data-deliver-action="hover"]');
const clearButton = document.querySelector('[data-deliver-action="clear"]');

clickButton.addEventListener('click', () => square.click(), false);

hoverButton.addEventListener('click', () => {

  let hover = new Event('mouseover');
  square.dispatchEvent(hover);

}, false);

clearButton.addEventListener('click', clearSquare, false);
.square {
display: block;
width: 120px;
height: 120px;
margin: 12px 6px;
text-align: center;
font-family: arial, helvetica, sans-serif;
font-weight: bold;
font-size: 14px;
text-transform: uppercase;
overflow: hidden;
cursor: pointer;
}

button {
display: block;
width: 160px;
margin: 6px;
cursor: pointer;
}

.square {
color: rgb(255, 0, 0);
background-color: rgb(255, 0, 0);
}

.square[data-received-action="click"] {
background-color: rgb(255, 255, 0);
}

.square[data-received-action="hover"] {
color: rgb(255, 255, 255);
background-color: rgb(255, 125, 0);
}
<div class="square" tabindex="0"></div>

<button type="button" data-deliver-action="click">Click the Square</button>
<button type="button" data-deliver-action="hover">Hover over the Square</button>
<button type="button" data-deliver-action="clear">Clear Square</button>
Rounin
  • 27,134
  • 9
  • 83
  • 108
  • This answer conflates two non alike things: `onmouseover != :hover`. It isn't simulating anything, it's just doing a normal thing. – Caleb Nov 04 '19 at 08:04
  • This question is nothing to do with CSS. It isn't about `:hover`. I am addressing how javascript can simulate a human user *positioning* a mouse pointer over an element in the same way that `.click()` simulates a human user clicking on an element. – Rounin Nov 04 '19 at 08:52
  • Is my use of the verb **hover** confusing you with the CSS pseudo-class `:hover`? If so, I am happy to update the verb to another like **pointer-touch**. – Rounin Nov 04 '19 at 08:58
  • I'm not confusing this with CSS. You can leave CSS and `:hover` out of it. The same problem still applies, you are conflating `.hover()` with `.onmouseover()`, one of which can be triggered manually, one that cannot. This isn't simulating anything, it's just doing the one of those two things that can be done at all. – Caleb Nov 04 '19 at 10:49
  • First you write: _"This answer conflates two non alike things: `onmouseover != :hover`"_. Then, when I responded _"This question is nothing to do with CSS"_, you write _"You can leave CSS and `:hover` out of it"_. Which `:hover` were you referring to the first time around, if not the CSS `:hover`? – Rounin Nov 04 '19 at 13:52
  • Re: _"This isn't simulating anything."_ We can all see that it is. Just as `element.click()` computationally simulates a human clicking on an element, this method computationally simulates a human positioning a pointer over an element. – Rounin Nov 04 '19 at 13:53
  • Connecting A→C and B→C so that either trigger method causes the same function to run is not the same as A triggering B. That distinction (and the fact that there are good reasons _not_ to be able to trigger B by anything but an actual B) is being papered over in this answer at, I think, the expense of people having a clear understanding of the actual constraints they are working under. – Caleb Nov 05 '19 at 05:26
  • Do you value methods like `.click()`, `.focus()` and `.blur()`? If you do, then you surely see merit in a `.pointertouch()` method? I would contend that there is great utility in being able to execute mouse actions computationally which are normally user-executed. I'm not sure if you agree with this or not. – Rounin Nov 05 '19 at 12:49