New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Event Handler on React Component not invoked when React Component is rendered inside a Web Component #9242

Open
nilshartmann opened this Issue Mar 23, 2017 · 9 comments

Comments

Projects
None yet
10 participants
@nilshartmann

nilshartmann commented Mar 23, 2017

Do you want to request a feature or report a bug?
Bug

What is the current behavior?
A React Component with an Event Handler (for example onClick) is rendered inside a Web Component. When the Component is clicked the Event does not receive the React Component (specified callback is not invoked)

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://jsfiddle.net or similar (template: https://jsfiddle.net/reactjs/69z2wepo/).

You can reproduce it with Web Component example contained in the react repository (https://github.com/facebook/react/blob/master/examples/webcomponents/index.html): Replace the 'a' element with a button and add for example an onClick event handler.

You can find a modified version of the Web Component example (based on the 15.4.2 codebase - https://github.com/facebook/react/blob/v15.4.2/examples/webcomponents/index.html) here:
https://gist.github.com/nilshartmann/3a520920e5fc920bfde49e077ad3beab#file-index-html-L50

What is the expected behavior?
The event handler should be called.

For testing I have modified getEventTarget.js to return the target from the path property of the nativeEvent (instead of the "original" target from the nativeEvent). With this addition it works -
the Event Handler is called.

You can find the modified version also in the gist: https://gist.github.com/nilshartmann/3a520920e5fc920bfde49e077ad3beab#file-geteventtarget-js-L6

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
15.4.x and 16.x
I've tested in Chrome, Firefox and Safari. I don't know if it works in previous versions of React (don't think so)

@DeanBDean

This comment has been minimized.

Show comment
Hide comment
@DeanBDean

DeanBDean Mar 23, 2017

@nilshartmann Should path be composedPath() instead?

https://hayato.io/2016/shadowdomv1/#getting-event-path

By the way, this almost entirely solves an issue I was having where events were not being captured by a web component that encapsulated a ReactDOM.

DeanBDean commented Mar 23, 2017

@nilshartmann Should path be composedPath() instead?

https://hayato.io/2016/shadowdomv1/#getting-event-path

By the way, this almost entirely solves an issue I was having where events were not being captured by a web component that encapsulated a ReactDOM.

@mgrdevport

This comment has been minimized.

Show comment
Hide comment
@mgrdevport

mgrdevport Apr 10, 2017

@DeanBDean You are right. We were using Chrome to investigate the event bubbling issue months ago, which gave us access to the event.path property. We are using the webcomponentsjs polyfill to make the shadow dom available in all browsers. Today the polyfill (shadyDom) provides us the composedPath() function, so we should maybe change it to the following:

// If encapsulated in a Web Component use the composed Event path
if(nativeEvent.composedPath && nativeEvent.composedPath()) {
    return nativeEvent.composedPath()[0];
}

mgrdevport commented Apr 10, 2017

@DeanBDean You are right. We were using Chrome to investigate the event bubbling issue months ago, which gave us access to the event.path property. We are using the webcomponentsjs polyfill to make the shadow dom available in all browsers. Today the polyfill (shadyDom) provides us the composedPath() function, so we should maybe change it to the following:

// If encapsulated in a Web Component use the composed Event path
if(nativeEvent.composedPath && nativeEvent.composedPath()) {
    return nativeEvent.composedPath()[0];
}
@bthallion

This comment has been minimized.

Show comment
Hide comment
@bthallion

bthallion May 21, 2017

I'm having the same problem, is there a workaround for this currently?

bthallion commented May 21, 2017

I'm having the same problem, is there a workaround for this currently?

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Oct 4, 2017

Member

We should confirm whether it still happens on master with native web components.
(16.0.0 WC support is borked but I fixed it on master.)

Member

gaearon commented Oct 4, 2017

We should confirm whether it still happens on master with native web components.
(16.0.0 WC support is borked but I fixed it on master.)

@larkintuckerllc

This comment has been minimized.

Show comment
Hide comment
@larkintuckerllc

larkintuckerllc Oct 8, 2017

First, I have also observed this first hand with React 16.0.0 (today). Also confirmed that a fellow opened up a related issue and wrote a working temporary fix, https://www.npmjs.com/package/react-shadow-dom-retarget-events .

While I do not see a use case for web components in my React applications, I am considering using React in building more complicated web components to be delivered to other platforms (I am thinking for WordPress bloggers; or similar).

larkintuckerllc commented Oct 8, 2017

First, I have also observed this first hand with React 16.0.0 (today). Also confirmed that a fellow opened up a related issue and wrote a working temporary fix, https://www.npmjs.com/package/react-shadow-dom-retarget-events .

While I do not see a use case for web components in my React applications, I am considering using React in building more complicated web components to be delivered to other platforms (I am thinking for WordPress bloggers; or similar).

@rytisbac

This comment has been minimized.

Show comment
Hide comment
@rytisbac

rytisbac Oct 13, 2017

Same problem here... Created component with react and want to include it to other sites - similar as iframe. The only way it can work is to retarget events. But I think it realy hurts performace

rytisbac commented Oct 13, 2017

Same problem here... Created component with react and want to include it to other sites - similar as iframe. The only way it can work is to retarget events. But I think it realy hurts performace

@robdodson

This comment has been minimized.

Show comment
Hide comment
@robdodson

robdodson Oct 17, 2017

Does React use event delegation to listen for clicks on React components? If so I imagine the shadow boundary would get in the way of that... Just want to make sure I understand the problem :)

robdodson commented Oct 17, 2017

Does React use event delegation to listen for clicks on React components? If so I imagine the shadow boundary would get in the way of that... Just want to make sure I understand the problem :)

@xastor

This comment has been minimized.

Show comment
Hide comment
@xastor

xastor Nov 22, 2017

The react-shadow-dom-retarget-events module works, but has a few problems of its own. If I'm correct, it picks up the native events on the shadow dom element, and then directly calls the react component event handlers (onClick, etc.. ) using those native events, instead of synthetic events. I think that because of this, stopPropagation() does not work.

It would be nice to see the React team pick this issue up and provide a proper fix. Shadow dom is gaining momentum! :-)

I've been thinking and maybe it would make sense to attach the global React event handlers to the element returned by getRootNode() instead of to the document?

https://developer.mozilla.org/en-US/docs/Web/API/Node/getRootNode

xastor commented Nov 22, 2017

The react-shadow-dom-retarget-events module works, but has a few problems of its own. If I'm correct, it picks up the native events on the shadow dom element, and then directly calls the react component event handlers (onClick, etc.. ) using those native events, instead of synthetic events. I think that because of this, stopPropagation() does not work.

It would be nice to see the React team pick this issue up and provide a proper fix. Shadow dom is gaining momentum! :-)

I've been thinking and maybe it would make sense to attach the global React event handlers to the element returned by getRootNode() instead of to the document?

https://developer.mozilla.org/en-US/docs/Web/API/Node/getRootNode

@marionebl

This comment has been minimized.

Show comment
Hide comment
@marionebl

marionebl Feb 5, 2018

Is there interest in a fix based on the suggestions by @nilshartmann? I'd be happy to contribute the required changes and new tests if required.


Edit:
If I understand correctly @xastor's suggestion is closely related to #2043, which appears to be the more general approach to fix this.

Reading the lengthy discussion of #8117, which was the last implementation attempt for #2043, I guess that redesigning the event propagation system to support multiple roots is a sprawling/hard to implement change.

marionebl commented Feb 5, 2018

Is there interest in a fix based on the suggestions by @nilshartmann? I'd be happy to contribute the required changes and new tests if required.


Edit:
If I understand correctly @xastor's suggestion is closely related to #2043, which appears to be the more general approach to fix this.

Reading the lengthy discussion of #8117, which was the last implementation attempt for #2043, I guess that redesigning the event propagation system to support multiple roots is a sprawling/hard to implement change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment