wildhoney / reactshadow Goto Github PK
View Code? Open in Web Editor NEW:beginner: Utilise Shadow DOM in React with all the benefits of style encapsulation.
Home Page: https://react-shadow.herokuapp.com/
License: MIT License
:beginner: Utilise Shadow DOM in React with all the benefits of style encapsulation.
Home Page: https://react-shadow.herokuapp.com/
License: MIT License
Just call appendChild on the ShadowRoot itself. The importNode doesn't do anything and neither does the template.
https://github.com/Wildhoney/ReactShadow/blob/master/component/ReactShadow.js#L43
Hi, is it possible to render a react portal into a shadow dom? I assigned an id to a div element within the ShadowDom but it cannot find it
The redux example currently fudges a bit by connecting the component outside the ShadowDOM and then manually passing the props through to the components within the ShadowDOM. This works okay for the top level components but not as a general pattern with an app that implements redux. It would be more useful if the example showed how to adjust ShadowDOM to pass the redux store context through to child components.
I wonder though why ShadowDOM forwards router context through by default but not the redux store context. Is this something that the project is willing to modify?
Errors:
Uncaught TypeError: Cannot read property 'createShadowRoot' of null
TypeError: this._shadowRoot.querySelector is not a function(โฆ)
Chrome 51
Chrome (as of this writing version 42) can't cache and de-duplicate style blocks that contain @import statements inside ShadowRoots.
This means that each react component will download the .css file if it doesn't have cache headers, and that the browser won't de-duplicate the <style> declarations which means creating those components will be really expensive as each one is parsing the stylesheet again.
Instead you want to write the css inline, or I suppose xhr it down and cache the string.
@Wildhoney
I have this simple rendering of shadow DOM
render() { return ( <ShadowDOM include={['test.css']}> <div> <input type="text" value={this.props.templateName} onChange={this.handleChange.bind(this)}/> <button onClick={this.saveTemplate.bind(this)}>SAVE</button> </div> </ShadowDOM> ); }
Could you help me why the css not reflecting in test.css?
test.css
:host input{ width: 300px; }
Also what is the purpose of props.theme? The documentation doesn't really explain its purpose
Hey, thank you for this wonderful library. ๐
Is there an example of how to use react-shadow with styled-components? I'm using client side React and my styles are not applied. I tried both options of styling a React
component but the border
prop doesn't even show up inside the styles of the devtools.
import 'styled-components/macro'
const Test = () => <div css={`border: solid 1px black;`}>Test</div>
or via an actual styled-component:
import styled from 'styled-components'
import root from 'react-shadow';
export const Test = styled.div`
border: solid 1px black;
`
export default function ShadowStyles() {
return (
<root.div>
<Test> Test </Test>
</root.div>
);
}
The ShadowDom
doesn't seem to work on edge? I've also tried adding pollyfill but that didn't fix too.
public render() {
console.log("application state:", this.props);
try {
return (
<div>
<ShadowDOM include={ browser.extension.getURL('/styles/main.css') }>
<div>
{this.currentPanel()}
</div>
</ShadowDOM>
</div>
);
} catch (ex) {
console.log(ex);
throw ex;
}
}
Please suggest
Thanks
I'm having issues integrating a react app in the shadow dom with packages that use the ReactDOM.findDOMNode function to access a specific node in the react app.
That function will definitely not be used since the app is in the shadow dom, however I'm curious if anyone has ran into this and what you use for the workaround to access the node by its ref?
Using react-bootstrap modal and ReactShadow, I have a rendered DOM like this
<div>
#shadow-root<open>
<main>
<div data-reactid=".2">
<div data-reactid=".1">
<div data-reactid=".1.1">
</div>
</div>
</div>
</main>
<script>
<div data-reactid=".4">
<div data-reactid=".3">
<div data-reactid=".3.1">
</div>
</div>
</div>
</script>
</div>
The translatedId
doesn't really get mapped correctly, as .1.1
will be replaced as .4.1
rather than .3.1
. I wonder if there is any solution that is based on event.path
rather than finding the element by reactid
?
Besides, thank you for the great work!
Hello. I am working on being able to get the initial position and width/height of shadowDOM elements. If you look at this codesandbox https://codesandbox.io/s/delicate-dust-77yqk (courtesy of @Asjas). As you can see on first load the width and height is 0, 0
and only after re-rendering that we can see the actual width and height.
It seems that a contenteditable
<div>
within ReactShadow
does not fire an onSelect
event. This event is usually fired when you click anywhere within a contenteditable
.
I'm actually not certain whether this is a problem with the Shadow DOM spec or a problem with react-shadow
, but I thought there might be some insight here into the problem. I've made a minimal codepen that illustrates the issue: https://codepen.io/anon/pen/JJPBaL?editors=1011
If you click within the red area (outside the Shadow DOM), you'll see a log in the console, but if you click within the blue area (inside the Shadow DOM), you don't see anything written to the console.
Sample code to illustrate the issue provided below. Basically, ShadowDOM is eating the componentWillUnmount propagation somehow. This prevents binding events to the DOM. Is this by design?
/*
index.js {
import React from 'react'
import {init} from "./ShadowDomBug"
init();
// press Unmount Me button to remove component from DOM
// expected console:
// ShadowDomBug.js:66 ini
// ShadowDomBug.js:72 unMountShadowDomBug
// ShadowDomBug.js:9 1 BindDOMEventListeners
// ShadowDomBug.js:9 1 BindDOMEventListeners
// ShadowDomBug.js:21 2 AnotherBindDOMEventListeners
// actual console:
// ShadowDomBug.js:66 ini
// ShadowDomBug.js:72 unMountShadowDomBug
// ShadowDomBug.js:9 1 BindDOMEventListeners
}
*/
import React, {Component} from 'react';
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import ShadowDOM from 'react-shadow'
class BindDOMEventListeners extends Component {
componentWillUnmount() {
// called every time
console.log('1 BindDOMEventListeners')
// window.removeEventListener('keydown', ...);
}
render() {
return (<div>{this.props.children}</div>);
}
}
class AnotherBindDOMEventListeners extends Component {
componentWillUnmount() {
// never called
console.log('2 AnotherBindDOMEventListeners')
// window.removeEventListener('keydown', ...);
}
render() {
return (<div> no children </div>);
}
}
export class ShadowDomBug extends Component {
render() {
return (
<BindDOMEventListeners>
<ShadowDOM>
<div>
<BindDOMEventListeners>
<AnotherBindDOMEventListeners/>
<div>
<button onClick={this.props.unMountMe}>Unmount Me</button>
</div>
</BindDOMEventListeners>
</div>
</ShadowDOM>
</BindDOMEventListeners>
);
}
}
ShadowDomBug.propTypes = {
unMountMe: PropTypes.func
};
ShadowDomBug.defaultProps = {
unMountMe: unMountShadowDomBug
};
export const domRootId = 'ShadowDomBug';
export function init() {
let root = document.getElementById(domRootId);
if (!root) {
root = document.createElement('div');
root.id = domRootId;
root.setAttribute('id', domRootId);
document.body.appendChild(root);
console.log('ini')
ReactDOM.render(<ShadowDomBug/>, root);
}
}
export function unMountShadowDomBug() {
console.log('unMountShadowDomBug')
ReactDOM.unmountComponentAtNode(document.getElementById(domRootId))
}
ReactShadow currenlty throws an error at runtime when used under browserify with React. It tries to use window.React which doesnt exist. A small shim to work with browserify will be very nice.
Getting a TypeError: this.getDOMNode(...).parentNode.createShadowRoot is not a function
when loading the page.
http://caniuse.com/#feat=shadowdom
Might need to detect and use webkitCreateShadowRoot()
instead as seen here:
http://soledadpenades.com/2014/01/02/shadow-dom-in-firefox/
Edit: looks like Firefox Nightly with a flag is required to use :(
I am building a chrome extension and am injecting code directly in the page. To avoid conflicting styles, I have utilized the react-shadow package and have been mostly successful in isolating the CSS. However, I am still getting issues with leakage of styles into the page.
For instance, in Gmail my extension looks like this:
But in Stack Overflow it looks like this:
I looked at the rendered HTML in the browser and it seems like there is still leakage of the styling on the html and body tags from the page into my page. Does anyone know why this might be the case?
Error related to https://github.com/Wildhoney/ReactShadow/blob/master/src/react-shadow.js#L293
and might some others..
The event retargeting code seems to be using querySelector against the top level document, not the parent component. I think it just wants to use this.getDOMNode().parentNode ?
https://github.com/Wildhoney/ReactShadow/blob/master/component/ReactShadow.js#L87
It's not clear why the element is duplicated inside a script tag, or why the content is wrapped inside a <main>
. This means React is updating twice as many DOM nodes though, and putting yourself as a child of script just makes you display: none, it doesn't do anything else.
Thanks for your work on this project. Just wanted to bring your attention to a small typo. Should be type
rather than tyle
.
Can you please provide an example of using scss styles (how do I configure the webpack?)
Thanks
Hi, the Heroku demo at http://react-shadow.herokuapp.com/ is currently HTTP 503.
I am trying to figure out what library works best for me. Both ReactShadow and styled-components are solving same problem though with a bit different approach (using shadow DOM vs generating obfuscated classes). Is there any advantage in using ReactShadow instead of styled-components?
I can see that built-in styled-components
support was added in 637149b, but I am wondering as this library depends on styled-components
directly (as seen here), would this not mean that the StyleSheetManager
created here would always be the StyleSheetManager
coming from the styled-components
version this library depends on (currently v4.4.1), not the version that the user of this library is depending upon (potentially styled-components
v5+)?
I may be overlooking the following, so let me know if these measures mean that the version the library renders is indeed the version the user of the library is depending upon:
require
, instead of importing it statically.styled-components
version you are depending on in this library is a dev dependency (which might only be being actually used in the examples, and it isn't part of the build output).I ask this a I want to update react-shadow
to v14.2.0+, and styled-components
to v5, but I want to make sure that its not going to introduce any weird bugs because the StyleSheetManager
injected isn't coming from the same styled-components
version as the components I'm creating.
Thanks for your time!
Hi @Wildhoney ,
Seems Im getting some issues on IE and Firefox
node.createShadowRoot is not a function
Is this only built for chrome??
Since React seems to invent the wheel themselves in regards to styling, maybe it is interesting to take a look at the CSS Shadow Parts specification and see if that can be implemented / polyfilled.
I am using a MuiThemeProvider from 'material-ui/styles/MuiThemeProvider' that passes a prop to components that subscribe using muiThemeable from 'material-ui/styles/muiThemeable'. However, the Provider props are not passed thru the ShadDOM down to children. Workaround is to wrap Provider again after ShadowDOM. Which is OK for for me however, propagating the props would be more elegant. Is this by design?
Hey,
It'd be nice to add TypeScript definitions to the project. I can make a PR if needed.
EDIT: Looking at how compact the src/
is, it might even be worth switching the project to TypeScript, if you feel up to it
I have an issue using react links inside the shadow dom component like this
<ShadowDOM include={['/zion_resources/widgets/header.css']}> <div> <Link className="item" activeClassName="active" to="preview"> <img src="/img/icons/zion.icon.tb_tablet.svg" alt="" width="23px"/> </Link> </div> </ShadowDOM>
Throws an error s rendered outside of a router context cannot navigate.
Any workarounds for this?
I'm excited to try out the lib, but I know shadow dom is not widely supported yet.
Are you polyfilling older versions, or does this only work in Chrome and Safari?
In HTML5 this is the default:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style
I am trying to use ReactShadow on IE11 but it doesn't seem to work. I get the following error in console:
Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined.
You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports. Check your code at index.tsx:55.
Line 55 contains the closing tag of the shadow root this:
<shadowRoot.section>
...
</shadowRoot.section>
Are there any plans to support IE11 in the future or does anybody know how to fix this? I am using webcomponentsjs, proxy-polyfill and other polyfills for explorer, but that doesn't seem to fix the issue.
Thanks
We get the error message: "ReactShadow: Passed child must be a concrete HTML element rather than another React component."
/*
index.js {
import React from 'react'
import {init} from "./ShadowDomBug"
init();
// expected output
// hello, world
// actual output error
// ReactShadow: Passed child must be a concrete HTML element rather than another React component.
}
*/
import React, {Component} from 'react';
import ReactDOM from 'react-dom'
import ShadowDOM from 'react-shadow'
class MyComponent extends Component {
render() {
return (<div>{this.props.children}</div>);
}
}
export class ShadowDomBug extends Component {
render() {
return (
<ShadowDOM>
<MyComponent>
<div>
hello, world
</div>
</MyComponent>
</ShadowDOM>
);
}
}
export const domRootId = 'ShadowDomBug';
export function init() {
let root = document.getElementById(domRootId);
if (!root) {
root = document.createElement('div');
root.id = domRootId;
root.setAttribute('id', domRootId);
document.body.appendChild(root);
console.log('ini')
ReactDOM.render(<ShadowDomBug/>, root);
}
}
It seems the context of elements inside of ShadowDOM seem to have issues with React-Redux. I was using Redux-Fractal to create local state components that I was embedding into a ShadowDOM component. Unfortunately, the library erred out on a call to context.store.getState() due to the store property being undefined.
I haven't had time to see if this is an issue related to Redux plugins, or Redux its self, and I'm not sure if the library was ever built to play nicely with Redux, but I would appreciate this issue resolved. I'll try to offer more information when I have the chance.
Hello,
I would like to use shadow dom and add icons inside this shadow dom but I can't make it works.
<div>
<ShadowDOM include={['https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css']}>
<div>
<i className="fa fa-comments fa-2x"></i>icon
</div>
</ShadowDOM >
</div>
, document.getElementById('root'));`
When running the code above, I have a square icon. It seems the font itself is missing. How can I add the font ?
Thanks for the help
Click events work beautifully, but ketboard events are displatched but never recieved by Reat
The Shadodom with unsupported browser like firefox and edge
may cause trouble with CSS issues. As of firefox documentation
A polyfilled Shadow DOM using the webcomponents.js polyfill doesn't actually encapsulate style, so the styles might bleed through. Be aware that sites built using the polyfill might look different when running in an environment that does support native Shadow DOM.
We just encounterd the CSS Issue when we were using Shadow Dom
with firefox
latest version.
Is there any work around for this?
I'm mounting Facebook's Draft Editor within a ShadowDOM
. For the most part this works fine except when I try to do a focus()
.
I've trimmed the problem down in CodePen to illustrate the issue:
https://codepen.io/michael_cox/pen/OmBPBm
When you click on the Focus
button, it throws the error Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'
. From tracing through the code it looks like it is a valid element, but I might be misunderstanding things. Admittedly this could be an issue with Draft making certain assumptions about the environment that it's running in, but I'm hoping for a simpler solution I might be missing on the ShadowDOM
side?
I'm trying to create a higher order component for this, e.g.:
import React from "react";
import ShadowDOM from "react-shadow";
const withShadow = (...include) => (Component) => {
return (props) => {
return (
<ShadowDOM include={include}>
<Component {...props} />
</ShadowDOM>
);
};
};
export default withShadow;
Usage:
const AppWrapper = _.flowRight(
withStore(reducers),
withShadow("path/to/app.css")
)(App);
ReactDOM.render(<AppWrapper />, ...);
Unfortunately I get an error:
ReactShadow: Passed child must be a concrete HTML element rather than another React component.
I don't see this documented, but I see that it's explicit in the source for this module. Is there a reason I can't use a component? Is it something that's possible to fix? I don't mind contributing, but I'm curious about the reason this is a limitation today.
This works:
import React from 'react'
import ReactShadow from 'react-shadow'
export default React.createClass({
mixins: [ReactShadow],
cssDocuments: ['styles/style.css'],
render: function() { ... }
})
This does not:
import React from 'react'
import ReactShadow from 'react-shadow'
export default class FavList extends React.Component {
mixins: [ReactShadow]
cssDocuments: ['styles/style.css']
constructor (_) {
super(_)
}
render() { ... }
}
Am trying to insert a .less file into a div, but shadow dom throwing a error as .less unsupported.
Hy!
I want to use React.ReactShadow with LinkedStateMixin, but it doesn't work, the state dont updateing.
No errors in console :(
Example:
http://jsbin.com/donaponata/1/edit?js,output
Working without ReactShadow:
http://jsbin.com/xaxigepacu/1/edit?js,output
I use React 0.12.2
Wondering how much of the v1 SDOM spec is supported here.
https://github.com/polymer/polymer/tree/2.0-preview#scoped-styling
https://developers.google.com/web/fundamentals/getting-started/primers/shadowdom
Hello Wildhoney,
Maybe I am coming a bit late I discovered your project this week.
Regarding the example you provided within the project, you have been able to create a build including a few folder including the css/country.css
When using webpack, depending on the configuration, the css files are retrieved from import at the head of js files, but are not retrieved directly from within a React Component ex:
Would you please provide your webpack configuration to create the build you did, it would help me to understand how did you export your country.css successfully without any regular import at the head of the file.
If you are still around, thank you in advance ;)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.