Design System Sharing
Strategies for sharing design systems, component libraries, and visual consistency across independently deployed micro-frontends.
You are an expert in sharing design systems across micro-frontend architectures. You help teams maintain visual consistency, reuse UI components, and distribute design tokens across independently built and deployed frontend applications without creating tight coupling. ## Key Points 1. **Design tokens** — colors, spacing, typography, shadows — the lowest-level primitives. 2. **Base components** — buttons, inputs, cards, modals — framework-specific or framework-agnostic. 3. **Patterns and layouts** — page templates, navigation patterns, form layouts. - **Semantic versioning** — breaking changes bump the major version. - **Multiple live versions** — the CDN or package registry hosts v1, v2, v3 simultaneously. - **Deprecation windows** — old versions are supported for a defined period. 1. **Tokens are the foundation** — even if teams use different component libraries or frameworks, shared tokens ensure visual consistency. Start with tokens before building shared components. 2. **Prefix all tokens** — use a namespace like `--ds-` to avoid collisions with app-specific CSS custom properties. 3. **Publish components with no side effects** — the design system package should be fully tree-shakeable. Importing `Button` should not pull in `Modal`. 4. **Support multiple frameworks or go framework-agnostic** — if teams use React, Vue, and Angular, either ship wrapper packages for each or use Web Components. 5. **Pin versions in micro-frontends, not in the shell** — each team decides when to upgrade. The token CSS can be `latest` (additive only), but component libraries should be pinned. 6. **Run visual regression tests** — automated screenshot comparison catches unintended visual changes before they reach production. ## Quick Example ```html <!-- Works in any framework --> <ds-button variant="primary" size="md">Add to Cart</ds-button> ```
skilldb get micro-frontend-skills/Design System SharingFull skill: 317 linesDesign System Sharing — Micro-Frontends
You are an expert in sharing design systems across micro-frontend architectures. You help teams maintain visual consistency, reuse UI components, and distribute design tokens across independently built and deployed frontend applications without creating tight coupling.
Overview
A micro-frontend architecture splits the UI across teams, but users expect a cohesive visual experience. A shared design system provides that cohesion. The challenge is distributing shared components and tokens in a way that allows independent versioning, does not force lockstep deployments, and works across different frameworks.
The design system in a micro-frontend context typically has three layers:
- Design tokens — colors, spacing, typography, shadows — the lowest-level primitives.
- Base components — buttons, inputs, cards, modals — framework-specific or framework-agnostic.
- Patterns and layouts — page templates, navigation patterns, form layouts.
Core Concepts
Token-First Architecture
Design tokens are the most portable layer. They can be expressed as CSS custom properties, JSON, or platform-specific formats (iOS, Android). In a micro-frontend system, tokens are the safest thing to share because they carry no framework dependency and are inherently backward-compatible when extended.
Versioning Strategy
The design system is a shared dependency. Teams must be able to upgrade at their own pace. This requires:
- Semantic versioning — breaking changes bump the major version.
- Multiple live versions — the CDN or package registry hosts v1, v2, v3 simultaneously.
- Deprecation windows — old versions are supported for a defined period.
Distribution Models
| Model | Pros | Cons |
|---|---|---|
| npm package | Familiar, version-pinned, tree-shakeable | Requires rebuild to update |
| CDN-hosted CSS/JS | Update without rebuilding consumers | Cache invalidation complexity |
| Module Federation remote | Runtime sharing, single instance | Webpack-specific |
| Web Components | Framework-agnostic | Larger bundle per component |
Implementation Patterns
Design Tokens as CSS Custom Properties
/* @myorg/design-tokens/tokens.css — distributed via CDN or npm */
:root {
/* Colors */
--ds-color-primary: #0052cc;
--ds-color-primary-hover: #0041a3;
--ds-color-secondary: #6554c0;
--ds-color-surface: #ffffff;
--ds-color-background: #f4f5f7;
--ds-color-text: #172b4d;
--ds-color-text-subtle: #6b778c;
--ds-color-border: #dfe1e6;
--ds-color-error: #de350b;
--ds-color-success: #00875a;
/* Spacing */
--ds-space-xs: 4px;
--ds-space-sm: 8px;
--ds-space-md: 16px;
--ds-space-lg: 24px;
--ds-space-xl: 32px;
/* Typography */
--ds-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
--ds-font-size-sm: 0.875rem;
--ds-font-size-md: 1rem;
--ds-font-size-lg: 1.25rem;
--ds-font-size-xl: 1.5rem;
--ds-font-weight-normal: 400;
--ds-font-weight-medium: 500;
--ds-font-weight-bold: 700;
/* Elevation */
--ds-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.1);
--ds-shadow-md: 0 4px 8px rgba(0, 0, 0, 0.1);
--ds-shadow-lg: 0 8px 16px rgba(0, 0, 0, 0.15);
/* Border radius */
--ds-radius-sm: 4px;
--ds-radius-md: 8px;
--ds-radius-lg: 12px;
--ds-radius-full: 9999px;
}
Tokens for Shadow DOM (Micro-Frontends Using Web Components)
// CSS custom properties pierce Shadow DOM, so tokens work automatically.
// Each micro-frontend's shadow root can reference:
const style = `
.button {
background: var(--ds-color-primary);
color: white;
padding: var(--ds-space-sm) var(--ds-space-md);
border-radius: var(--ds-radius-sm);
font-family: var(--ds-font-family);
}
`;
Shared Component Library via npm
// @myorg/design-system — React component library
// src/Button/Button.tsx
import React from "react";
import styles from "./Button.module.css";
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "primary" | "secondary" | "ghost";
size?: "sm" | "md" | "lg";
}
export function Button({
variant = "primary",
size = "md",
children,
...props
}: ButtonProps) {
return (
<button
className={`${styles.button} ${styles[variant]} ${styles[size]}`}
{...props}
>
{children}
</button>
);
}
/* src/Button/Button.module.css */
.button {
font-family: var(--ds-font-family);
font-weight: var(--ds-font-weight-medium);
border: none;
cursor: pointer;
border-radius: var(--ds-radius-sm);
transition: background-color 0.15s ease;
}
.primary { background: var(--ds-color-primary); color: white; }
.primary:hover { background: var(--ds-color-primary-hover); }
.secondary { background: var(--ds-color-secondary); color: white; }
.ghost { background: transparent; color: var(--ds-color-primary); }
.sm { padding: var(--ds-space-xs) var(--ds-space-sm); font-size: var(--ds-font-size-sm); }
.md { padding: var(--ds-space-sm) var(--ds-space-md); font-size: var(--ds-font-size-md); }
.lg { padding: var(--ds-space-md) var(--ds-space-lg); font-size: var(--ds-font-size-lg); }
Sharing Components via Module Federation
// webpack.config.js — design system as a federated remote
const { ModuleFederationPlugin } = require("webpack").container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: "designSystem",
filename: "remoteEntry.js",
exposes: {
"./Button": "./src/Button/Button",
"./Card": "./src/Card/Card",
"./Modal": "./src/Modal/Modal",
"./tokens": "./src/tokens.css",
},
shared: {
react: { singleton: true, requiredVersion: "^18.0.0" },
"react-dom": { singleton: true, requiredVersion: "^18.0.0" },
},
}),
],
};
// Consumer micro-frontend
import { Button } from "designSystem/Button";
Framework-Agnostic Components via Web Components
// @myorg/design-system-wc — Web Component wrappers
class DsButton extends HTMLElement {
static get observedAttributes() {
return ["variant", "size", "disabled"];
}
constructor() {
super();
this.attachShadow({ mode: "open" });
}
connectedCallback() {
this._render();
}
attributeChangedCallback() {
this._render();
}
_render() {
const variant = this.getAttribute("variant") || "primary";
const size = this.getAttribute("size") || "md";
const disabled = this.hasAttribute("disabled");
this.shadowRoot.innerHTML = `
<style>
:host { display: inline-block; }
button {
font-family: var(--ds-font-family);
font-weight: var(--ds-font-weight-medium);
border: none;
cursor: ${disabled ? "not-allowed" : "pointer"};
border-radius: var(--ds-radius-sm);
opacity: ${disabled ? "0.5" : "1"};
}
.primary { background: var(--ds-color-primary); color: white; }
.secondary { background: var(--ds-color-secondary); color: white; }
.sm { padding: var(--ds-space-xs) var(--ds-space-sm); font-size: var(--ds-font-size-sm); }
.md { padding: var(--ds-space-sm) var(--ds-space-md); font-size: var(--ds-font-size-md); }
.lg { padding: var(--ds-space-md) var(--ds-space-lg); font-size: var(--ds-font-size-lg); }
</style>
<button class="${variant} ${size}" ${disabled ? "disabled" : ""}>
<slot></slot>
</button>
`;
}
}
customElements.define("ds-button", DsButton);
<!-- Works in any framework -->
<ds-button variant="primary" size="md">Add to Cart</ds-button>
Multi-Version Coexistence
<!-- Shell loads the token layer (always latest) -->
<link rel="stylesheet" href="https://cdn.example.com/design-tokens/latest/tokens.css" />
<!-- Catalog team pins to design-system v2 -->
<script>
import("https://cdn.example.com/design-system/v2/components.js");
</script>
<!-- Checkout team already migrated to v3 -->
<script>
import("https://cdn.example.com/design-system/v3/components.js");
</script>
Visual Regression Testing Across Micro-Frontends
// chromatic.config.js or Playwright visual test
// Test the design system in isolation AND composed in the shell
// 1. Component-level (design system repo)
test("Button renders all variants", async ({ page }) => {
await page.goto("/storybook/iframe.html?id=button--all-variants");
await expect(page).toHaveScreenshot("button-variants.png");
});
// 2. Integration-level (shell repo)
test("Shell with catalog and checkout micro-frontends", async ({ page }) => {
await page.goto("/catalog/product/123");
await expect(page).toHaveScreenshot("catalog-product-page.png");
});
Best Practices
- Tokens are the foundation — even if teams use different component libraries or frameworks, shared tokens ensure visual consistency. Start with tokens before building shared components.
- Prefix all tokens — use a namespace like
--ds-to avoid collisions with app-specific CSS custom properties. - Publish components with no side effects — the design system package should be fully tree-shakeable. Importing
Buttonshould not pull inModal. - Support multiple frameworks or go framework-agnostic — if teams use React, Vue, and Angular, either ship wrapper packages for each or use Web Components.
- Pin versions in micro-frontends, not in the shell — each team decides when to upgrade. The token CSS can be
latest(additive only), but component libraries should be pinned. - Run visual regression tests — automated screenshot comparison catches unintended visual changes before they reach production.
- Provide a Storybook or equivalent — a living style guide lets all teams browse available components and their API without reading source code.
Common Pitfalls
- CSS specificity wars — if the design system uses low-specificity selectors and a micro-frontend overrides them, the results are unpredictable. Use CSS Modules or Shadow DOM for deterministic specificity.
- Breaking changes without major version bumps — renaming a token or changing a component's DOM structure breaks consumers silently. Follow semantic versioning strictly.
- Design system team as bottleneck — if every component change requires the design system team to act, velocity drops. Allow teams to propose and contribute components via pull requests.
- Duplicated styles at runtime — if three micro-frontends each bundle the same CSS from the design system, the user downloads it three times. Externalize shared CSS via CDN or Module Federation.
- Inconsistent icon sets — icons are easy to overlook. Include them in the design system to prevent each team from importing different icon libraries.
- Theme switching race conditions — if the shell switches from light to dark theme, micro-frontends that cache token values in JavaScript (rather than reading CSS variables live) will show stale colors.
Core Philosophy
Visual consistency across independently deployed applications is the user-facing test of a micro-frontend architecture. Users do not care about your team structure — they see one product and expect it to look like one product. A shared design system is the mechanism that delivers this consistency, and design tokens are its most portable, framework-agnostic foundation.
Tokens are the safest layer to share globally. CSS custom properties like --ds-color-primary carry no framework dependency, work inside Shadow DOM, and are backward-compatible when new tokens are added. Components are valuable but carry framework opinions. Start with tokens, build shared components once teams agree on a framework strategy, and use Web Components if teams use different frameworks.
Version the design system and let teams upgrade at their own pace. A forced simultaneous upgrade across all micro-frontends is a coordinated deployment — exactly what micro-frontends are designed to avoid. Publish multiple major versions simultaneously, set deprecation windows, and track which teams are on which versions. The design system team's job is to make upgrading easy, not mandatory.
Anti-Patterns
-
Forcing lockstep design system upgrades — requiring all teams to adopt the latest version simultaneously defeats independent deployment; support multiple live versions with defined deprecation windows.
-
Not prefixing design tokens — using generic names like
--primaryor--spacingrisks collisions with app-specific CSS custom properties; always use a namespace like--ds-. -
Duplicating design system CSS in every micro-frontend bundle — if three micro-frontends each bundle the same CSS, the user downloads it three times; externalize shared CSS via CDN or Module Federation.
-
Making the design system team a bottleneck — if every component change requires the design system team to act, velocity drops; allow teams to propose and contribute components via pull requests.
-
Using different icon libraries per team — each team independently choosing an icon set produces visual inconsistency; include icons in the design system to ensure a unified icon language.
Install this skill directly: skilldb add micro-frontend-skills
Related Skills
Deployment
Independent deployment patterns for micro-frontends including CI/CD pipelines, versioning, rollback, and environment strategies.
Iframe Composition
iFrame-based micro-frontend composition for maximum isolation between independently deployed frontend applications.
Module Federation
Webpack Module Federation for sharing code and dependencies across independently deployed micro-frontends at runtime.
Routing
Cross-application routing strategies for micro-frontends including shell-controlled routing, distributed routing, and URL contracts.
Shared State
Cross-application state sharing patterns for micro-frontends including event buses, shared stores, and URL-based state.
Single Spa
Single-SPA framework for orchestrating multiple JavaScript micro-frontends within a single page application shell.