Last active
March 24, 2020 08:56
-
-
Save jmfrancois/a728521a1cee561e5fb8370b2882a863 to your computer and use it in GitHub Desktop.
This gist let you use React into shadowDOM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* IMPORTANT NOTE. | |
* Because react use synthetic event we have to patch the shadowDOM | |
* The following patch has to be applied just after the attachShadow | |
* and you must ban the use document.createElement. Use shadowRoot.createElement instead. | |
* Source: https://github.com/facebook/react/issues/9242 | |
*/ | |
function changeOwnerDocumentToShadowRoot(element, shadowRoot) { | |
Object.defineProperty(element, 'ownerDocument', {value: shadowRoot}); | |
} | |
function augmentAppendChildWithOwnerDocument(elem, shadowRoot) { | |
const origAppChild = elem.appendChild; | |
const propDesc = Object.getOwnPropertyDescriptor(elem, 'appendChild'); | |
if (!propDesc || propDesc.writable) { | |
Object.defineProperty(elem, 'appendChild', { | |
value: function (child) { | |
changeOwnerDocumentToShadowRoot(child, shadowRoot); | |
origAppChild?.call(elem, child); | |
} | |
}); | |
} | |
} | |
function augmentCreateElementWithOwnerDocument(shadowRoot, createFnName) { | |
const originalCreateFn = document[createFnName]; | |
shadowRoot[createFnName] = (...args) => { | |
const element = originalCreateFn.call(document, ...args); | |
changeOwnerDocumentToShadowRoot(element, shadowRoot); | |
augmentAppendChildWithOwnerDocument(element, shadowRoot); | |
return element; | |
}; | |
} | |
export function patchShadowForReact(shadowRoot) { | |
augmentCreateElementWithOwnerDocument(shadowRoot, 'createElement'); | |
augmentCreateElementWithOwnerDocument(shadowRoot, 'createElementNS'); | |
augmentCreateElementWithOwnerDocument(shadowRoot, 'createTextNode'); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import ReactDOM from 'react-dom'; | |
import patchShadowForReact from './patchShadowForReact'; | |
function MyButton(props) { | |
return <button type={prop.type || 'button'} onClick={e => props.onClick(e)}>{ props.label }</button> | |
} | |
class ShadowButton extends HTMLElement { | |
constructor() { | |
super(); | |
} | |
connectedCallback() { | |
if (!this.shadowRoot) { | |
this.attachShadow({ mode: "open" }); | |
patchShadowForReact(this.shadowRoot); | |
this.root = this.shadowRoot.createElement('div'); | |
this.shadowRoot.appendChild(this.root) | |
this.render(); | |
} | |
} | |
onClick(e) { | |
e.preventDefault(); | |
e.stopPropagation(); | |
console.log('click'); | |
} | |
render() { | |
function Demo() { | |
return ( | |
<React.Fragment> | |
<h1>Hello button</h1> | |
<MyButton label="Hello world" onClick={(e) => this.onClick(e)} /> | |
</React.Fragment> | |
); | |
} | |
ReactDOM.render(<Demo />, this.root); | |
} | |
} | |
customElements.define('my-button', ShadowButton); | |
const btn = document.createElement('my-button'); | |
document.body.appendChild(btn); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment