52

I'm trying to simulate a .click() event on a React element but I can't figure out why it is not working (It's not reacting when I'm firing the event).

I would like to post a Facebook comment using only JavaScript but I'm stuck at the first step (do a .click() on div[class="UFIInputContainer"] element).

My code is:

document.querySelector('div[class="UFIInputContainer"]').click();

And here's the URL where I'm trying to do it: https://www.facebook.com/plugins/feedback.php...

P.S. I'm not experienced with React and I don't know really if this is technically possible. It's possible?

EDIT: I'm trying to do this from Chrome DevTools Console.

Alfonso
  • 1,125
  • 1
  • 13
  • 23
  • 2
    Possible duplicate of [Trigger a button click from a non-button element](http://stackoverflow.com/questions/6367339/trigger-a-button-click-from-a-non-button-element) – Tschallacka Oct 17 '16 at 16:08
  • @Tschallacka answer (http://stackoverflow.com/a/6367609/5997711) seems could work, but unfortunately I'm not getting any result. – Alfonso Oct 17 '16 at 16:39

10 Answers10

71

React tracks the mousedown and mouseup events for detecting mouse clicks, instead of the click event like most everything else. So instead of calling the click method directly or dispatching the click event, you have to dispatch the down and up events. For good measure I'm also sending the click event but I think that's unnecessary for React:

const mouseClickEvents = ['mousedown', 'click', 'mouseup'];
function simulateMouseClick(element){
  mouseClickEvents.forEach(mouseEventType =>
    element.dispatchEvent(
      new MouseEvent(mouseEventType, {
          view: window,
          bubbles: true,
          cancelable: true,
          buttons: 1
      })
    )
  );
}

var element = document.querySelector('div[class="UFIInputContainer"]');
simulateMouseClick(element);

This answer was inspired by Selenium Webdriver code.

carlin.scott
  • 6,214
  • 3
  • 30
  • 35
49

With react 16.8 I would do it like this :

const Example = () => {
  const inputRef = React.useRef(null)
        
  return (
    <div ref={inputRef} onClick={()=> console.log('clicked')}>
      hello
    </div>
  )
}
    

And simply call

inputRef.current.click()
Poptocrack
  • 2,879
  • 1
  • 12
  • 28
Elfen
  • 903
  • 7
  • 8
21

Use refs to get the element in the callback function and trigger a click using click() function.

class Example extends React.Component{
  simulateClick(e) {
    e.click()
  }
  render(){
    return <div className="UFIInputContainer"
    ref={this.simulateClick} onClick={()=> console.log('clicked')}>
      hello
      </div>
  }
}

ReactDOM.render(<Example/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Pranesh Ravi
  • 18,642
  • 9
  • 46
  • 70
  • Thank you for your answer, but how you would apply that on this URL: [link](https://www.facebook.com/plugins/feedback.php?api_key=516792821822250&channel_url=https%3A%2F%2Fstaticxx.facebook.com%2Fconnect%2Fxd_arbiter%2Fr%2FP5DLcu0KGJB.js%3Fversion%3D42%23cb%3Df32e78989ee3c64%26domain%3Dproductodelasemana.top%26origin%3Dhttps%253A%252F%252Fproductodelasemana.top%252Ff21b47c88d96f0c%26relation%3Dparent.parent&colorscheme=light&href=https%3A%2F%2Fproductodelasemana.top&locale=en_US&numposts=5&sdk=joey&skin=light&version=v2.8&width=100%25#) ? can't get it working. – Alfonso Oct 17 '16 at 16:22
  • 8
    `e.click is not a function` – Mote Zart Apr 04 '19 at 16:10
  • 1
    it should be e.target.click() – toing_toing Jul 09 '19 at 23:15
  • This did not work for me, however `e.props` contains whatever functions are mapped onto the element. In my instance it was a checkbox with `onChange`, so in simulateClick `e.props.onChange()` worked perfectly. – Michael Aaron Wilson Aug 17 '20 at 21:47
5

A slight adjustment to @carlin.scott's great answer which simulates a mousedown, mouseup and click, just as happens during a real mouse click (otherwise React doesn't detect it).

This answer adds a slight pause between the mousedown and mouseup events for extra realism, and puts the events in the correct order (click fires last). The pause makes it asynchronous, which may be undesirable (hence why I didn't just suggest an edit to @carlin.scott's answer).

async function simulateMouseClick(el) {
  let opts = {view: window, bubbles: true, cancelable: true, buttons: 1};
  el.dispatchEvent(new MouseEvent("mousedown", opts));
  await new Promise(r => setTimeout(r, 50));
  el.dispatchEvent(new MouseEvent("mouseup", opts));
  el.dispatchEvent(new MouseEvent("click", opts));
}

Usage example:

let btn = document.querySelector("div[aria-label=start]");
await simulateMouseClick(btn);
console.log("The button has been clicked.");

Note that it may require page focus to work, so executing in console might not work unless you open the Rendering tab of Chrome DevTools and check the box to "emulate page focus while DevTools is open".

joe
  • 3,752
  • 1
  • 32
  • 41
5

If you don't define a class in your component, and instead you only declare:

function App() { ... }

In this case you only need to set up the useRef hook and use it to point/refer to any html element and then use the reference to trigger regular dom-events.

import React, { useRef } from 'react';

function App() {
  const inputNameRef = useRef()
  const buttonNameRef = useRef()
  
  function handleKeyDown(event) {
    // This function runs when typing within the input text,
    // but will advance as desired only when Enter is pressed
    if (event.key === 'Enter') {
      // Here's exactly how you reference the button and trigger click() event,
      // using ref "buttonNameRef", even manipulate innerHTML attribute
      // (see the use of "current" property)
      buttonNameRef.current.click()
      buttonNameRef.current.innerHTML = ">>> I was forced to click!!"
    }
  }
  
  function handleButtonClick() {
    console.log('button click event triggered')
  }
  
  return (
    <div>
      <input ref={inputNameRef} type="text" onKeyDown={handleKeyDown}  autoFocus />
      <button ref={buttonNameRef} onClick={handleButtonClick}>
      Click me</button>
    </div>
  )
}

export default App;
F. Müller
  • 3,969
  • 8
  • 38
  • 49
4

Kind of a dirty hack, but this one works well for me whereas previous suggestions from this post have failed. You'd have to find the element that has the onClick defined on it in the source code (I had to run the website on mobile mode for that). That element would have a __reactEventHandlerXXXXXXX prop allowing you to access the react events.

let elem = document.querySelector('YOUR SELECTOR');
//Grab mouseEvent by firing "click" which wouldn't work, but will give the event
let event;
likeBtn.onclick = e => {
  event = Object.assign({}, e);
  event.isTrusted = true; //This is key - React will terminate the event if !isTrusted
};
elem.click();
setTimeout(() => {
  for (key in elem) {
    if (key.startsWith("__reactEventHandlers")) {
      elem[key].onClick(event);
    }
  }
}, 1000);

  
Gilad Barner
  • 721
  • 8
  • 15
3

Inspired from previous solution and using some javascript code injection it is also possibile to first inject React into the page, and then to fire a click event on that page elements.

let injc=(src,cbk) => { let script = document.createElement('script');script.src = src;document.getElementsByTagName('head')[0].appendChild(script);script.onload=()=>cbk() }
injc("https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js",() => injc("https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js",() => {

class ReactInjected extends React.Component{
  simulateClick(e) {
    e.click()
  }
  render(){
    return <div className="UFIInputContainer"
    ref={this.simulateClick} onClick={()=> console.log('click injection')}>
      hello
      </div>
  }
}
ReactDOM.render(<ReactInjected/>, document.getElementById('app'))

} ))
<div id="app"></div>
loretoparisi
  • 15,724
  • 11
  • 102
  • 146
1

Using React useRef Hooks you can trigger a click event on any button like this:

export default const () => {

    // Defining the ref constant variable
    const inputRef = React.useRef(null);

    // example use
    const keyboardEvent = () => {
      inputRef.current.handleClick(); //Trigger click
    }

    // registering the ref
    return (
       <div ref={inputRef} onClick={()=> console.log('clicked')}>
          hello
       </div>
    )
}
70ny
  • 748
  • 1
  • 7
  • 22
tam
  • 352
  • 1
  • 3
  • 13
1

This answer was inspired by carlin.scott code. However, it works only with focusin event in my case.

const element = document.querySelector('element')
const events = ['mousedown', 'focusin']

events.forEach(eventType =>
    element.dispatchEvent(
        new MouseEvent(eventType, { bubbles: true })
    )
)
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
0

Actually we say focus an input rather than click on an input (technically speaking). And what you have here (div[class="UFIInputContainer"]) is an input, not a button! (image below)

enter image description here

Focus an element in React Functional Component

function CustomTextInput(props) {
  // textInput must be declared here so the ref can refer to it
  const textInput = useRef(null);
  
  function handleClick() {
    textInput.current.focus();
  }

  return (
    <div>
      <input
        type="text"
        ref={textInput} />
      <input
        type="button"
        value="Focus the text input"
        onClick={handleClick}
      />
    </div>
  );
}

To find this example and more, kindly check the docs

underflow
  • 1,545
  • 1
  • 5
  • 19