Skip to content

Styles are wrong when used inside a shadow root #2612

Open
@chriscoomber

Description

@chriscoomber

Is there an existing issue for this?

  • I have searched the existing issues

Describe the issue

I placed a react-native-web component in a shadow root, and the styles were wrong. Specifically, these components have the correct class names, but the style sheet seems to have not been loaded.

<Button color='red' title='Test'/>

looks like

Screenshot 2023-11-23 at 10 30 22

In the chrome debugger, its DOM element looks like:

<button role="button" class="css-view-175oi2r r-transitionProperty-1i6wzkk r-userSelect-lrvibr r-cursor-1loqt21 r-touchAction-1otgn73 r-borderRadius-1jkafct" type="button" style="background-color: rgb(255, 0, 0); transition-duration: 0s;"><div dir="auto" class="css-text-146c3p1 r-color-jwli3a r-fontWeight-majxgm r-padding-edyy15 r-textAlign-q4m81j r-textTransform-tsynxw">Test</div></button>

however Chrome can't resolve any of these classes - only the host's stylesheet is being applied.

Expected behavior

Should look like
Screenshot 2023-11-23 at 10 31 13

Steps to reproduce

  1. Quickstart with Create React App

  2. Obtain a ShadowDom react component (either react-shadow or roll your own).

I had the same issue with react-shadow (which was presumably written by someone who knows what they're doing!), but for the sake of this issue I'm using the following wrapper as it's a simpler repro - please let me know if I'm making a glaring mistake as I'm not an experienced web developer.

function ShadowDomWrapper({children}) {
  const shadowHost = useRef();
  const reactRoot = useRef();

  useEffect(() => {
    if (shadowHost.current) {
      if (!reactRoot.current) {
        const shadowRoot = shadowHost.current.attachShadow({mode: "open"});
        reactRoot.current = createRoot(shadowRoot);
      }
      reactRoot.current.render(children);
    }
  });

  return <div ref={shadowHost}></div>
}
  1. Render a react-native-web component in and outside the shadow root to see how they differ:
function App() {
  return (
    <div className="App">
      <header className="App-header">
        ...other stuff...
        <Button color='red' title='Test'/>
        <ShadowDomWrapper>
          <Button color='red' title='Test'/>
        </ShadowDomWrapper>
        ...other stuff...

Test case

https://codesandbox.io/p/sandbox/react-native-web-shadow-dom-repro-5gy7vw

Additional comments

I saw some related issues, e.g. #1517 and it seems support for the shadow DOM was added with 0.18. It's very possible that I'm just missing a step, but there's no documentation for how to get this working! How does react-native-web provide the stylesheets to the root node of the app? How do I do this for the shadow root?

Why am I trying to do this?

I have a component library written in react-native, for cross-platform compatibility between our react-native app and our next.js app. When rendering components from the library in next.js, they are suddenly affected by CSS stylesheets from the next.js app, which can break the styling. The components are already styled with the style prop - I do not need external styling so I want to isolate them from the styling added by the website, hence the use of shadow dom. However, I seem to be losing the RNW styles too!

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions