Giter Site home page Giter Site logo

Comments (11)

bcanseco avatar bcanseco commented on August 19, 2024 15

@remysabliet I have used two options successfully.

import as string with css-to-string-loader

.my-style {
  background-color: red;
}
test: /\.css$/,
use: [
  {loader: 'css-to-string-loader'},
  {loader: 'css-loader'},
],
import stylesheet from './styles.css';

const SomewhereInsideReactShadow = () => (
  <div>
    <style dangerouslySetInnerHTML={{__html: stylesheet}}/>
    <div class="my-style">
  </div>
);

Dynamic import with style-loader

This one is more complex. The normal way to import CSS is to use style-loader, which drops your <style> tag into document.head. Obviously that doesn't work for shadow DOM things since the <style> needs to be inside the shadow DOM.

Fortunately, style-loader has an insertInto option that lets you specify where you want your styles imported.

use: [
  {
    loader: 'style-loader',
    options: {
      insertInto: () => {
        return document.querySelector('#my-shadow-dom-anchor').shadowRoot;
      },
    },
  },
  {loader: 'css-loader'},
],

Yay! You don't need to make your own <style> element anymore. The downside here is that the element with ID my-shadow-dom-anchor needs to exist BEFORE the

import './styles.css';

statement is reached, and it needs to already have a shadow root attached. I wasn't able to get it working with ReactShadow, but you can do it if you make the shadow DOM yourself.

// MyComponentInsideAShadowDOM.jsx
import './styles.css';

const MyComponentInsideAShadowDOM= () => (
  <div class="my-style"/>
);
// App.jsx
import ReactDOM from 'react-dom';
import retargetEvents from 'react-shadow-dom-retarget-events';

// Create your anchor div. Must have same ID that style-loader will be looking for.
const anchor = document.createElement('div');
anchor.id = 'my-shadow-dom-anchor';

// Give it a shadow DOM tree
const shadowRoot = anchor.attachShadow({mode: 'open'});
retargetEvents(shadowRoot);

// Add it to the <body>
document.body.appendChild(anchor);

// Now you can import your component and render it inside the shadow DOM anchor
const Component = (await import(
  /* webpackMode: "eager" */
'./MyComponentInsideAShadowDOM.jsx'
)).default;
ReactDOM.render(<Component/>, anchor);

You may need babel-plugin-syntax-dynamic-import.

from reactshadow.

Wildhoney avatar Wildhoney commented on August 19, 2024

There is no build for the CSS in the example.

It uses the include attr on <ReactShadow /> but of course you could use Webpack to import the CSS, or use a CSS-in-JS solution such as styled-components without any problems.

from reactshadow.

remysabliet avatar remysabliet commented on August 19, 2024

Thank you for your quick answer.

Well, in my understanding of shadow dom, we can apply like a full css file to a shadow DOM node ( maybe I am wrong?). If I start declaring all in-line, with a huge amount of css code it would be pretty ugly (too many css properties).

Considering the first assumption to be true, now if for example I wanna apply a whole css file to a component and its child (the whole component embedded by <shadowDOM include.. > , when building the application with Webpack, using a standard css loader, he won't include the css file in the built version and so it won't work as your include={} attribute is not an import.
So i was wondering how did you built your example ?
In webpack I am having below conf for css :
{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }

would you have an idea? ( i am pretty new to web-dev so this question will probably looks simple for you)

from reactshadow.

Wildhoney avatar Wildhoney commented on August 19, 2024

I don't have an example off-hand as I don't use it in the example, but yes your assumption is correct and so your component could well be something like the following with the correct Webpack setup:

import styles from './styles.css';

With the JSX as:

<section>
  <div>
    <style type="text/css">{styles}</style>
    etc...
  </div>
</section>

from reactshadow.

remysabliet avatar remysabliet commented on August 19, 2024

I see, so I will try to make my webpack works better than, thanks ;)

from reactshadow.

Wildhoney avatar Wildhoney commented on August 19, 2024

I forget which one it is exactly, but if you use either css-loader or style-loader on their own, you'll get the desired import behaviour, otherwise one of them automatically injects the CSS into the html.

from reactshadow.

remysabliet avatar remysabliet commented on August 19, 2024

Let’s say I have a simple react project with 2 files:
src/index.js

  import "./stylesheets/slide3.css";
 ...
  <ShadowDOM include="./stylesheets/slide3.css">
      <div id="div1">
        <p> First Div </p>
        <div id="div2">
          <p> second Div </p>
        </div>
      </div>
    </ShadowDOM>);

src/stylesheets/slide3.css

#div1 p{
color: blue;
}

#div2 p{
  color: red;
}

How would you manage that file import to works in both local (react-scripts start ) and also compatible after having build the application (react-scripts build ) and launch the server in local (serve –s build)?

Why that question is that, by looking at your code, it considers the file passed in include property as an URL. So if i refers to a local file in my workspace ( include=”./stylesheets/slide3.css”) it wont work and i will get the error in console:

GET http://localhost:3000/stylesheets/slide3.css 404 (Not Found)

Obviously this URL doesn’t exist and even if I would try the full URL (including absolute path on my laptop) it would give something like this, and it doesn’t work either):

GET http://localhost:3000/Users/remysabliet/proj/react-proj/remysabliet/src/stylesheets/slide3.css 404 (Not Found)react-shadow.js:844

Moreover, If we deploy using react build, the website structure is different and give something like below:
https://ibb.co/eCgM5U

Subsequently, i would set <shadowDOM include=”static/css/stylesheets/slide3.css”> ...
but it is not working either, can't retrieve the css file.

I am looking for a simple solution to make it works contextly (like import './stylesheets/slide3.css’
How would you advice me to do so?

I have also tried your second solution using

import slide3 from './stylesheets/slide3.css'
and declaring <slide..>{slide3}</style>

Example on sandbox: https://codesandbox.io/s/k0qky1loy5

and I am getting below error :

_invariant Violation
Objects are not valid as a React child (found: object with keys {}). If you meant to render a collection of children, use an array instead.This is some text!

Thanks in advance for your support

from reactshadow.

remysabliet avatar remysabliet commented on August 19, 2024

I already passed 2 days on this before posting. I wonder how people succeeded to make it work that simple, except by doing all in-line code.

from reactshadow.

pactera-admindev-remy avatar pactera-admindev-remy commented on August 19, 2024

Hello bcanseco,

Thank you for your help, really appreciate it.

I succeeded to make your Solution 1 works 👍
I have make some research about this dangerouslySetInnerHTML property , as far as I have understood, it allows XSS attack.. but as far as we include only CSS styles, is there a security issue?

As a countermeasure, there is the DOMPurify plugin which allows to sanitarize injected HTML, but I guess we don't need it as far as we only include CSS, am I wrong ?

Regarding method 2 I understand that you are not using ReactShadow anymore but regular JS, I would go this way only if can't make sure that the dangerouslySetInnerHTML is not that dangerous in our case (Injecting CSS Style).

If you have some feedback on it, looking forward to hear it :)

from reactshadow.

bcanseco avatar bcanseco commented on August 19, 2024

@pactera-admindev-remy Afaik you're correct. As long as you only use dangerouslySetInnerHTML for styles and no user-submitted input, you should be good. Still not an ideal solution but it works.

from reactshadow.

Wildhoney avatar Wildhoney commented on August 19, 2024

Documented applying CSS styles in the new version.

from reactshadow.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.