How to add onclick event to a string rendered by dangerouslysetInnerHtml in reactjs? How to add onclick event to a string rendered by dangerouslysetInnerHtml in reactjs? reactjs reactjs

How to add onclick event to a string rendered by dangerouslysetInnerHtml in reactjs?


Caveat: This sounds like an X/Y problem, where the underlying problem (whatever it is) should be solved differently, so that you don't have to add a click handler to a DOM element created via dangerouslySetInnerHTML (ideally, so you don't have to create DOM elements via dangerouslySetInnerHTML at all). But answering the question you asked: (You've clarified the use case; solution #1 below applies and isn't poor practice.)

I don't think you can do that directly. Two solutions I can think of:

  1. Use delegated event handler on the div: Add a click handler on the div, but then only take action if the click passed through the b element.

  2. Use a ref on the div, and then hook the click handler up in componentDidMount and componentDidUpdate (finding the b element within the div via querySelector or similar), something along these lines:

Here's an example of #1:

<div onClick={this.clickHandler} dangerouslySetInnerHTML={this.createMarkup(string)}/>

...where clickHandler is

clickHandler(e) {    // `target` is the element the click was on (the div we hooked or an element    // with in it), `currentTarget` is the div we hooked the event on    const el = e.target.closest("B");    if (el && e.currentTarget.contains(el)) {        // ...do your state change...    }}

...or if you need to support older browsers without ParentNode#closest:

clickHandler(e) {    // `target` is the element the click was on (the div we hooked or an element    // with in it), `currentTarget` is the div we hooked the event on    let el = e.target;    while (el && el !== e.currentTarget && el.tagName !== "B") {        el = el.parentNode;    }    if (el && el.tagName === "B") {        // ...do your state change...    }}

...and where you bind clickHandler in the constructor (rather than using a property with an arrow function; why: 1, 2):

this.clickHandler = this.clickHandler.bind(this);

Live Example: