Skip to content

Instantly share code, notes, and snippets.

@DimitryDushkin
Last active December 23, 2020 07:48
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DimitryDushkin/c091d5a6c33e10641eef0828261d5398 to your computer and use it in GitHub Desktop.
Save DimitryDushkin/c091d5a6c33e10641eef0828261d5398 to your computer and use it in GitHub Desktop.
React v15 Shadow Dom events fix. Based on http://stackoverflow.com/a/37891448/297939. Unnecessery events removed and fix for multiple dispatches added.
export default function retargetEvents(el) {
// Here include necessary events' name to track
['onClick', 'onChange'].forEach(eventType => {
const transformedEventType = eventType.replace(/^on/, '').toLowerCase();
el.addEventListener(transformedEventType, event => {
for (let i in event.path) {
const item = event.path[i],
internalComponent = findReactInternal(item);
if (internalComponent && internalComponent._currentElement && internalComponent._currentElement.props) {
dispatchEvent(event, eventType, internalComponent._currentElement.props);
}
if (item == el) {
break;
}
}
});
});
}
function findReactInternal(item) {
let instance;
for (let key in item) {
if (item.hasOwnProperty(key) && ~key.indexOf('_reactInternal')) {
instance = item[key];
break;
}
}
return instance;
}
function dispatchEvent(event, eventType, itemProps) {
if (itemProps[eventType]) {
itemProps[eventType](event);
}
}
// =========================================================================
// index.js (mounting point of React)
import { render } from 'react-dom';
import App from './App.jsx';
import retargetEvents from './react-shadow-dom-fix.js';
const shadowRoot = document.querySelector('#ydf-cs-helper').createShadowRoot(),
appContainer = document.createElement('div');
shadowRoot.appendChild(appContainer);
render(<App />, appContainer);
// use the fix above
retargetEvents(shadowRoot);
@awwester
Copy link

awwester commented Aug 1, 2017

This is working pretty well for me, except that the onChange event seems to only dispatch when blur happens on a controlled element. When typing in the textbox the value shown in the textbox is updated, however the onCommentChange isn't dispatched until leaving the textbox.

<textarea value={this.state.comment} onChange={this.onCommentChange} />

onCommentChange = event => {
    console.log('setting comment... ', event.target.value);
    this.setState({ comment: event.target.value });
}

Curious if you have ran into this and/or if you have any ideas of why this happens?

@LukasBombach
Copy link

@awwester this is the proper native behavior, the browser fires the onChange event when the input is blurred, so technically it's correct. React works differently however and I have no idea yet how to fix it.

facebook/react#10422 (comment)

@LukasBombach
Copy link

A workaround would be to listen to onInput instead of onChange. We might event shim this and call onChange when onInput is triggered

I just did that and it works great. Updated and published my npm package

https://www.npmjs.com/package/react-shadow-dom-retarget-events

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