EVO React Components

MFE Shadow DOM Support

Guide for using Evo Components in MFE apps with shadow DOM

For more information about MFE publishing, see the MFE Publishing documentation

Overview

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

Problems & Solutions

1. Tailwind Variables

Guidance

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;

2. Portal Components

Implemented

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}>

3. Keyboard Navigation

Incomplete

Keyboard navigation doesn't work properly for Portal components. Full radix UI fix is pending.

Usage

To enable shadow DOM support in affected components:

  1. Open the component file (e.g. registry/evo-shadcn/ui/dialog.tsx)
  2. Uncomment the useShadowRoot import at the top
  3. Uncomment const shadowRoot = useShadowRoot() inside the component
  4. Uncomment the container={shadowRoot} prop on the Portal component

All 12 Portal components follow this same pattern.

Demo Repository

Complete working examples available at evo-experiment-spike-mfe-shadow