59

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.

2

10 Answers 10

81

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.

Sign up to request clarification or add additional context in comments.

9 Comments

Doesn't seem to work anymore, perhaps we need to send a "change" event?
This solution worked beautifully for a while but recently broke. Did you end up finding an alternative @information_interchange ?
If you guys could provide the version of React that started breaking this, that could help me address the issue with the solution.
Most of react apps listen to 'mousedown' event instead of 'click', so try mouseClickEvents = ['mousedown']
Agreed this no longer works
|
50

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()

5 Comments

@tam, you mean inputRef.current.handleClick() ??
@Gajen yeah. Looks like I have made a typo.
This is the right and best solution.. Thank You.. you saved my day :)
This is the best answer IMO
When I use this I get cannot read property click of null after it clicks once
20

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>

4 Comments

Thank you for your answer, but how you would apply that on this URL: link ? can't get it working.
e.click is not a function
it should be e.target.click()
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.
10

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".

2 Comments

This didn’t seem to work for me, maybe react detects it differently now?
Thank you so much, I was having trouble finding this despite knowing the equivalent for reactjs text fields.
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;

Comments

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);

  

5 Comments

This might be a dumb question, but how did you run it in “mobile” mode?
For me it was under __reactProps instead of __reactEventHandlers, but even activating the onClick this way didn't seem to work, or at least not completely.
Okay I figured it out, it seems you have to modify the event with one extra thing, add a property called nativeEvent = {detail:1}, your tactic works great now!
This code works in the console, but doesn't work when you run it in the actual code. How do I find the __reactProps or __reactEventHandlers via code?
Not sure, I've abandoned this code...
2

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>

Comments

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>
    )
}

Comments

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 })
    )
)

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.