Guide for using Evo Components in MFE apps with shadow DOM
For more information about MFE publishing, see the MFE Publishing documentation
React Evo Components don't work properly in MFE apps with shadow DOM due to style encapsulation. 13 components have opt-in fixes as commented code that you can uncomment to enable shadow DOM support.
Affected Components:
alert-dialog, context-menu, dialog, drawer, dropdown-menu, hover-card, menubar, popover, select, sheet, tooltip, use-shadow-root hook, focus-scope component
CSS variables don't cross shadow DOM boundaries.
Solution: Define all CSS variables using :host selector in your shadow DOM stylesheet.
:host, :root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
/* ... all other variables */
}Additionally, add these Tailwind CSS variables to your @theme inline block:
--tw-divide-y-reverse: 0;
--tw-border-style: solid;
--tw-font-weight: initial;
--tw-tracking: initial;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-translate-z: 0;
--tw-rotate-x: rotateX(0);
--tw-rotate-y: rotateY(0);
--tw-rotate-z: rotateZ(0);
--tw-skew-x: skewX(0);
--tw-skew-y: skewY(0);
--tw-space-x-reverse: 0;
--tw-gradient-position: initial;
--tw-gradient-from: #0000;
--tw-gradient-via: #0000;
--tw-gradient-to: #0000;
--tw-gradient-stops: initial;
--tw-gradient-via-stops: initial;
--tw-gradient-from-position: 0%;
--tw-gradient-via-position: 50%;
--tw-gradient-to-position: 100%;
--tw-shadow: 0 0 #0000;
--tw-shadow-color: initial;
--tw-inset-shadow: 0 0 #0000;
--tw-inset-shadow-color: initial;
--tw-ring-color: initial;
--tw-ring-shadow: 0 0 #0000;
--tw-inset-ring-color: initial;
--tw-inset-ring-shadow: 0 0 #0000;
--tw-ring-inset: initial;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-offset-shadow: 0 0 #0000;
--tw-blur: initial;
--tw-brightness: initial;
--tw-contrast: initial;
--tw-grayscale: initial;
--tw-hue-rotate: initial;
--tw-invert: initial;
--tw-opacity: initial;
--tw-saturate: initial;
--tw-sepia: initial;
--tw-drop-shadow: initial;
--tw-duration: initial;
--tw-ease: initial;Portals render to document.body by default, outside shadow DOM.
Solution: Uncomment the shadow DOM fixes in Portal components to render inside shadow root.
Before:
// import { useShadowRoot } from "@/hooks/use-shadow-root"
// const shadowRoot = useShadowRoot()
<DialogPortal> {/* <DialogPortal container={shadowRoot}> */}After:
import { useShadowRoot } from "@/hooks/use-shadow-root"
const shadowRoot = useShadowRoot()
<DialogPortal container={shadowRoot}>Keyboard navigation doesn't work properly for Portal components. Full radix UI fix is pending.
To enable shadow DOM support in affected components:
registry/evo-shadcn/ui/dialog.tsx)useShadowRoot import at the topconst shadowRoot = useShadowRoot() inside the componentcontainer={shadowRoot} prop on the Portal componentAll 12 Portal components follow this same pattern.
Complete working examples available at evo-experiment-spike-mfe-shadow