Skip to main content

StyleRootProvider

An advanced provider for controlling Emotion cache and shadow DOM styling

Submit feedback
github
import { StyleRootProvider } from '@uhg-abyss/web/ui/ThemeProvider';

The StyleRootProvider is an advanced component that gives you fine-grained control over how styles are injected into your application. It provides options for standard CSS injection or shadow DOM encapsulation, making it ideal for applications that need style isolation or custom styling strategies.

Common use cases

Abyss Parcels with shadow DOM

The most common use case for StyleRootProvider is with Abyss Parcels that use the built-in shadow DOM feature for complete style isolation. See Using with Abyss Parcels for more details.

import { StyleRootProvider } from '@uhg-abyss/web/ui/ThemeProvider';
import { ThemeProvider } from '@uhg-abyss/web/ui/ThemeProvider';
import { createTheme } from '@uhg-abyss/web/tools/theme';
const theme = createTheme('uhc');
export const MyParcel = () => (
<StyleRootProvider
useShadowDom
theme={theme}
cacheOptions={{ key: 'my-parcel' }}
>
<ThemeProvider theme={theme}>
<ParcelContent />
</ThemeProvider>
</StyleRootProvider>
);

Custom cache configuration

StyleRootProvider allows applications to customize the Emotion cache, which is particularly useful for setting a unique key or controlling style insertion. See Cache options for more details.

import { StyleRootProvider } from '@uhg-abyss/web/ui/ThemeProvider';
const App = () => (
<StyleRootProvider cacheOptions={{ key: 'my-app' }}>
{/* App content */}
</StyleRootProvider>
);

Other use cases

  • Micro-frontends that need to avoid style conflicts with host applications
  • Applications with custom styling requirements
  • Web components requiring style encapsulation

Cache options

The cacheOptions prop accepts the following properties from @emotion/cache:

interface CacheOptions {
// Unique identifier for the cache / defaults to 'abyss'
key?: string;
// Container to insert styles into (useful for shadow DOM)
container?: HTMLElement;
// DOM node to insert styles before
insertionPoint?: HTMLElement;
// Array of stylis plugins for custom CSS processing
stylisPlugins?: any[];
// Nonce security attribute for CSP
nonce?: string;
// Vendor-specific CSS property prefixing
prefix?: boolean;
// Speedy mode for faster insertions (default: true in production)
speedy?: boolean;
}

Key cache options

  • key: A unique identifier for the cache. This is important when using multiple instances of StyleRootProvider to prevent style collisions. Defaults to 'abyss' if not specified.

  • speedy: Controls Emotion's performance optimization mode:

    • When true: Faster style insertion using CSSOM APIs but less readable CSS (default in production)
    • When false: More readable CSS with better debugging but slower performance (default in development)
  • container: Specifies where styles should be inserted. Particularly useful for shadow DOM scenarios where styles need to be contained within the shadow root.

  • insertionPoint: Allows you to control where in the DOM styles are inserted, which can be important for style precedence. This is the recommended way to control style insertion order.

  • stylisPlugins: Enables custom CSS processing with Stylis plugins.

For more details on these options, refer to the Emotion Cache Documentation.

Using with Abyss Parcels

One of the primary use cases for StyleRootProvider is with Abyss parcels that need complete style isolation. When used with parcels configured with shadowDOM: true, StyleRootProvider automatically detects and uses the parcel's shadow DOM to create a style boundary.

The useShadowDom prop enables shadow DOM features, preventing styles from leaking between your parcel and the host application.

Note: The theme prop is required for proper font loading in shadow DOM mode.

Integration with the Parcel system

StyleRootProvider automatically integrates with the Abyss Parcel system:

  • Automatic Detection: When used within an Abyss Parcel, it detects the Parcel environment through the global __ABYSS_PARCEL_BUILD__ variable.

  • Shadow Root Integration: For Parcels with shadow DOM enabled (shadowDOM: true in Parcel config), it automatically uses the existing shadow root created by the Parcel system.

  • Style Scoping: All styles are properly scoped to the Parcel's shadow DOM, creating a complete style boundary.

  • Font Loading: The theme's fonts are automatically injected into the shadow DOM when the theme prop is provided.

Example: Parcel with shadow DOM

import { StyleRootProvider } from '@uhg-abyss/web/ui/ThemeProvider';
import { ThemeProvider } from '@uhg-abyss/web/ui/ThemeProvider';
import { createTheme } from '@uhg-abyss/web/tools/theme';
const theme = createTheme('uhc');
export const MyParcel = () => (
<StyleRootProvider
useShadowDom // Enable shadow DOM features
theme={theme} // Required for font loading in shadow DOM
cacheOptions={{
key: 'my-parcel', // Unique key for this parcel
speedy: process.env.NODE_ENV === 'production', // Better debugging in dev
}}
>
<ThemeProvider theme={theme}>
{/* Your parcel content here */}
</ThemeProvider>
</StyleRootProvider>
);

Best practices for Parcels

  • Always use a unique key in cacheOptions to prevent potential style collisions
  • Always provide the theme prop when using shadow DOM for proper font loading
  • Consider disabling speedy mode during development for better debugging
  • Use the same theme instance for both StyleRootProvider and ThemeProvider

Advanced shadow DOM options

The StyleRootProvider offers several advanced options for fine-tuning shadow DOM behavior.

Using an existing shadow root

If you already have a shadow root (for example, from a Web Component), you can pass it directly to the StyleRootProvider:

const MyComponent = () => {
const hostRef = useRef(null);
const [shadowRoot, setShadowRoot] = useState(null);
useEffect(() => {
if (hostRef.current) {
const root = hostRef.current.attachShadow({ mode: 'open' });
setShadowRoot(root);
}
}, []);
return (
<div ref={hostRef}>
{shadowRoot && (
<StyleRootProvider
shadowRoot={shadowRoot}
theme={theme}
cacheOptions={{ key: 'custom-shadow' }}
>
<ThemeProvider theme={theme}>
<Content />
</ThemeProvider>
</StyleRootProvider>
)}
</div>
);
};

Shadow root mode

You can control the mode of the shadow root with the shadowRootMode prop:

<StyleRootProvider
useShadowDom
shadowRootMode="closed" // 'open' (default) or 'closed'
theme={theme}
>
{/* content */}
</StyleRootProvider>

Constructable stylesheets

For better performance in browsers that support it, you can enable Constructable Stylesheets:

<StyleRootProvider useShadowDom useConstructableStylesheets theme={theme}>
{/* content */}
</StyleRootProvider>

StyleRootProvider Props

NameTypeDefaultRequiredDescription
cacheOptions
CreateThemeCacheOptions | undefined
--
Cache options for Emotion
children
React.ReactNode
-
Content to be wrapped with the style provider
onShadowRootCreated
(shadowRoot: ShadowRoot) => void
--
Optional callback when shadow root is created
shadowRoot
ShadowRoot | null
--
Existing shadow root to use
shadowRootMode
"open" | "closed"
'open'
-
Shadow root mode
theme
CreateThemeReturn
--
Required to load fonts in shadow DOM mode
useConstructableStylesheets
boolean
false
-
Whether to use constructable stylesheets
useShadowDom
boolean
false
-
Whether to use shadow DOM for style isolation
Whether to use shadow DOM encapsulation
Table of Contents