Clarity Angular and React Wrappers in Micro-Frontend: Custom Element Registry Collision and CSS Variable Scoping
0 reputation · 27 Feb 2025, 20:27 UTC
0 reputation · 27 Feb 2025, 20:27 UTC
Determine whether an Angular shell application can safely host React-based Clarity components without custom element registration conflicts or theming inconsistencies.
Both @clr/angular and @clr/react re-export the same underlying Web Components from @clr/ui, but each wrapper registers custom elements globally via customElements.define(). When different wrapper versions load (e.g., @clr/angular@6.2 and @clr/react@6.3), the second registration throws a DOMException unless manually guarded. Additionally, Clarity's theming relies on CSS custom properties set on :root; shadow DOM encapsulation in the core means framework-specific global styles cannot reliably override component internals without ::part() or declared CSS parts. VMware documents single-framework adoption only; mixing wrappers is not a supported configuration. Peer dependency ranges in wrappers often lag behind the core Web Components release cadence, increasing version mismatch risk.
customElements.define() calls when multiple Clarity framework wrappers share a single @clr/ui version?@clr/angular, @clr/react, and @clr/ui to eliminate registration collisions?30775 reputation · 28 Feb 2025, 01:12 UTC
Both @clr/angular and @clr/react re-export the same @clr/ui web components and each calls customElements.define() during module initialization. The second load throws DOMException: NotSupportedError if the tag is already registered.
Apply one of these guards at the earliest shared entry point (e.g., Angular shell main.ts or a shared bootstrap module):
// Option A: explicit check
const TAGS = ['clr-button', 'clr-input', 'clr-card', /* …all Clarity tags… */];
TAGS.forEach(tag => {
if (customElements.get(tag) === undefined) {
// safe to let the wrapper define it
}
});
// Option B: try/catch (catches any duplicate)
try {
customElements.define('clr-button', ClrButton);
} catch (e) {
if (e instanceof DOMException && e.name === 'NotSupportedError') {
// already registered — ignore
} else {
throw e;
}
}
Option A is preferable because it avoids the exception overhead and makes intent explicit. Generate the tag list from @clr/ui’s components.json or the wrapper’s exported component map to stay in sync across versions.
Clarity’s core web components read CSS custom properties from their host element or :root via standard inheritance through shadow DOM boundaries. Setting variables on the Angular shell’s :root (or a wrapper div that ancestors the React‑mounted components) propagates automatically:
:root {
--clr-primary: #0066cc;
--clr-background: #f8f9fa;
--clr-font-family: 'Inter', system-ui, sans-serif;
}
For internals exposed via ::part() (e.g., ::part(input), ::part(button)), add overrides in the shell’s global stylesheet:
clr-input::part(input) {
border-radius: 4px;
}
Do not use ::slotted(), ::shadow, or constructible stylesheets to reach non‑part internals — those paths are deprecated and will break.
Peer dependency ranges in @clr/angular and @clr/react often lag @clr/ui releases, so a single @clr/ui version must be enforced at the root:
// package.json (npm v7+)
{
"dependencies": {
"@clr/ui": "6.3.0",
"@clr/angular": "6.3.0",
"@clr/react": "6.3.0"
},
"overrides": {
"@clr/angular > @clr/ui": "6.3.0",
"@clr/react > @clr/ui": "6.3.0"
}
}
For Yarn 1.x/berry, use resolutions in package.json or packageExtensions in .yarnrc.yml. After install, verify with:
npm ls @clr/ui
# or
yarn list @clr/ui
Only one version should appear. If multiple remain, check transitive dependencies of other packages and extend overrides accordingly.
Which bundler and module format (ESM vs. CommonJS) does the Angular shell use for the React micro‑frontend entry point? The answer determines whether the guard runs before or after the React wrapper’s side effects execute, and whether customElements is shared across the same global scope.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.