Scoped Web Components
Scoped Web Components
🏃♂️ TL;DR
Scoped Web Components enable multiple applications with a different version of Cosmos to coexist on the same webpage and should be used whenever there is the slightest chance that an application is running in conjunction with other applications that also use Cosmos web components.
Overview
Micro frontends are a new emerging pattern in frontend architectures where a web application is decomposed into individual features, each owned and implemented by an independent team. Suddenly those micro applications will find themselves coexisting on the same webpage, trying to define Cosmos web components in the browser's custom elements registry using the custom element’s tag name and a reference to its constructor.
Typically the registration of a Component in the registry looks like this and is usually taken care of by Cosmos.
customElements.define(‘cosmos-button’, CosmosButton);The custom element registry is shared across applications that run on the same webpage and only allows a component with the same name to be registered once. While applications that rely on the same version of a Cosmos web component can share the same registered custom element, the dilemma starts when applications need to register a component with the same name but of a different version: any additional attempt to register a Cosmos component with the same tag name but a different constructor will be rejected by the custom element registry.
Until the web components standards support scoped custom element registries the only way to support different versions of Cosmos running on the same webpage is to scope the custom elements themselves: custom elements' tag names include version information and therefore can be uniquely identified and registered. A<cosmos-button>of version 9.7.0 will register as <cosmos-button-9-7-0> and therefore can coexist next to other buttons of different versions.
Usage
Import Cosmos web components @cosmos/web-scoped instead of @cosmos/web allows applications to use scoped web components. The versions of both packages are in sync, the features are the same and the API is interchangeable. Follow the Getting Started guide and replace @cosmos/web references with @cosmos/web-scoped.
💡 Pro Tip
Migration from unscoped to scoped web components only requires switching a projects dependency from @cosmos/web and @cosmos/web-scoped
import { h, render } from "preact";
import { CosmosButton } from "@cosmos/web-scoped-preact"; // v9.7.0
/**
* Renders
*
* <cosmos-button-9-7-0
* kind="tertiary"
* size="small"
* >
* Cosmos Button
* </cosmos-button-9-7-0>
*/
const app = (
<CosmosButton
kind='tertiary'
size='small'
>
Cosmos Button
</CosmosButton>
);
render(app, window.document.body);Scoped web components contain version information in their tag names: a <cosmos-button> turns into <cosmos-button-9-7-0> . While the library wrappers (e.g. @cosmos/web-scoped-preact) are taking care of rendering the correct tag names based on the version of the library. Updates to the tag names in Vanilla JavasScript applications have to be managed manually.
☝️ Watch out
Vanilla JavasScript applications have to manually keep HTML tag names of Cosmos web components in sync with the version that is used.
import {
defineCosmosButton,
defineCosmosText,
} from "@cosmos/web-scoped"; // v9.7.0
defineCosmosButton();
defineCosmosText();
# index.html
<cosmos-button-9-7-0
kind="tertiary"
size="small"
>
Cosmos Button
</cosmos-button-9-7-0>