Some checks failed
No response / noResponse (push) Has been cancelled
CI / Continuous releases (push) Has been cancelled
CI / test-dev (macos-latest) (push) Has been cancelled
CI / test-dev (ubuntu-latest) (push) Has been cancelled
CI / test-dev (windows-latest) (push) Has been cancelled
Maintenance / main (push) Has been cancelled
Scorecards supply-chain security / Scorecards analysis (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
101 lines
2.9 KiB
Markdown
101 lines
2.9 KiB
Markdown
# Shadow DOM
|
||
|
||
<p class="description">The shadow DOM lets you encapsulate parts of an app to keep them separate from global styles that target the regular DOM tree.</p>
|
||
|
||
## How to use the shadow DOM with Material UI
|
||
|
||
### 1. Styles
|
||
|
||
The shadow DOM is an API that provides a way to attach a hidden separated DOM to an element.
|
||
This is useful when you need to keep the structure, style, and behavior of different components separate from the rest of the code on the page, to prevent conflicts.
|
||
See [the MDN docs on the shadow DOM](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM) for more information.
|
||
The following code snippet shows how to apply styles inside of the shadow DOM:
|
||
|
||
```tsx
|
||
const container = document.querySelector('#root');
|
||
const shadowContainer = container.attachShadow({ mode: 'open' });
|
||
const shadowRootElement = document.createElement('div');
|
||
shadowContainer.appendChild(shadowRootElement);
|
||
|
||
const cache = createCache({
|
||
key: 'css',
|
||
prepend: true,
|
||
container: shadowContainer,
|
||
});
|
||
|
||
ReactDOM.createRoot(shadowRootElement).render(
|
||
<CacheProvider value={cache}>
|
||
<App />
|
||
</CacheProvider>,
|
||
);
|
||
```
|
||
|
||
### 2. Theme
|
||
|
||
Material UI components like Menu, Dialog, Popover, and others use the [Portal](/material-ui/react-portal/) component to render a new "subtree" in a container outside of current DOM hierarchy.
|
||
By default, this container is `document.body`.
|
||
But since the styles are applied only inside of the Shadow DOM, we need to render portals inside the Shadow DOM container as well:
|
||
|
||
```tsx
|
||
const theme = createTheme({
|
||
components: {
|
||
MuiPopover: {
|
||
defaultProps: {
|
||
container: shadowRootElement,
|
||
},
|
||
},
|
||
MuiPopper: {
|
||
defaultProps: {
|
||
container: shadowRootElement,
|
||
},
|
||
},
|
||
MuiModal: {
|
||
defaultProps: {
|
||
container: shadowRootElement,
|
||
},
|
||
},
|
||
},
|
||
});
|
||
|
||
// ...
|
||
|
||
<ThemeProvider theme={theme}>
|
||
<App />
|
||
</ThemeProvider>;
|
||
```
|
||
|
||
### 3. CSS theme variables (optional)
|
||
|
||
:::info
|
||
If you use **TypeScript**, you need to [extend the interface of the theme](/material-ui/customization/css-theme-variables/usage/#typescript) first.
|
||
:::
|
||
|
||
To use [CSS theme variables](/material-ui/customization/css-theme-variables/overview/) inside of the shadow DOM, you need to set the selectors for generating the CSS variables:
|
||
|
||
```diff
|
||
const theme = createTheme({
|
||
+ cssVariables: {
|
||
+ rootSelector: ':host',
|
||
+ colorSchemeSelector: 'class',
|
||
+ },
|
||
components: {
|
||
// ...same as above steps
|
||
}
|
||
})
|
||
```
|
||
|
||
Finally, set the `colorSchemeNode` prop using `shadowRootElement`, from step 1, as the value:
|
||
|
||
```diff
|
||
<ThemeProvider
|
||
theme={theme}
|
||
+ colorSchemeNode={shadowRootElement}
|
||
>
|
||
```
|
||
|
||
## Demo
|
||
|
||
In the example below you can see that the component outside of the shadow DOM is affected by global styles, while the component inside of the shadow DOM is not:
|
||
|
||
{{"demo": "ShadowDOMDemoNoSnap.js", "hideToolbar": true, "bg": true}}
|