Skip to content

Instantly share code, notes, and snippets.

@robertgonzales
Created December 12, 2017 03:03
  • Star 70 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save robertgonzales/b1966af8d2a428a8299663b92fb2fe03 to your computer and use it in GitHub Desktop.
Use React portals to render inside shadow dom and iframes
class Frame extends Component {
componentDidMount() {
this.iframeHead = this.node.contentDocument.head
this.iframeRoot = this.node.contentDocument.body
this.forceUpdate()
}
render() {
const { children, head, ...rest } = this.props
return (
<iframe {...rest} ref={node => (this.node = node)}>
{this.iframeHead && ReactDOM.createPortal(head, this.iframeHead)}
{this.iframeRoot && ReactDOM.createPortal(children, this.iframeRoot)}
</iframe>
)
}
}
<Frame head={<title>Hello World</title>}>
<h1>Hello World</h1>
</Frame>
class Shadow extends Component {
componentDidMount() {
this.shadowRoot = this.node.attachShadow({ mode: this.props.mode })
this.forceUpdate()
}
render() {
const { children, ...rest } = this.props
return (
<div {...rest} ref={node => (this.node = node)}>
{this.shadowRoot && ReactDOM.createPortal(children, this.shadowRoot)}
</div>
)
}
}
<Shadow mode="open">
<h1>Hello World</h1>
</Shadow>
@LinZap
Copy link

LinZap commented Jul 30, 2019

I'm trying this in Firefox 59.0.2 and the content appears for a split second and then disappears: https://codesandbox.io/s/4j72vl564x

Does anyone know how to solve this?

UPDATE: Fixed https://codesandbox.io/s/4lr7oxxrl7 🙂

I think get correct <body> node in <iframe> must be at the onLoad event

Thank you so much 🙂

@lucasterra
Copy link

Using React Hooks and createPortal:
https://codesandbox.io/s/iframe-demo-zd0b0

@saliyawi
Copy link

saliyawi commented Aug 7, 2020

This one really helpful, Thanks

@luisincrespo
Copy link

I'm trying this in Firefox 59.0.2 and the content appears for a split second and then disappears: https://codesandbox.io/s/4j72vl564x
Does anyone know how to solve this?
UPDATE: Fixed https://codesandbox.io/s/4lr7oxxrl7 🙂

I think get correct <body> node in <iframe> must be at the onLoad event

Thank you so much 🙂

This worked for me as well, thanks!

@bilobom
Copy link

bilobom commented Feb 14, 2021

I used the shadow dom to isolate Styles here is the functional component version of it:

const ShadowWrapper = (props) => {
  const { children, mode = "open", ...rest } = props;

  const ref = useRef();
  const [shadowRoot, setShadowRoot] = useState(null);

  useEffect(() => {
    setShadowRoot(ref.current.attachShadow({ mode }));
  }, []);

  return (
    <div {...rest} ref={ref}>
      {shadowRoot && ReactDOM.createPortal(children, shadowRoot)}
    </div>
  );
};

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