Web Component Theming
Styling third-party web components with platform design tokens, including live light/dark switching in the shadow DOM
Web components share the platform's look automatically: the sandbox delivers the active theme's design tokens (daisyUI-style CSS variables) and keeps them in sync live — including light/dark switches — without a reload.
How theme delivery works
- The sandbox page applies the active theme before your bundle runs, so components never paint unthemed.
- Theme changes (for example the user toggling dark mode) arrive as live bridge
messages; the sandbox updates its
data-themeattribute and your component can react through the SDK. - Because the sandbox blocks network access, the theme stylesheet is delivered
from the sandbox origin — components must adopt it as a
<link>, which the SDK handles for you.
Adopting the theme in a shadow DOM
Components render in shadow DOM, which does not inherit document stylesheets. Use the SDK helper once, at mount:
import { connect } from "@smallstack/web-component-sdk";
const client = connect(hostElement);
const stopTheming = client.adoptThemeStylesheets(shadowRoot);
// ...on unmount:
stopTheming();
client.disconnect();
adoptThemeStylesheets appends the theme's stylesheet links into your shadow root
and swaps them only when the URLs actually change — a plain light/dark switch keeps
the same stylesheet and restyles instantly through the token variables.
Styling with token variables
Write your styles against the platform variables, with fallbacks for standalone rendering:
.card {
background: var(--color-base-200, transparent);
color: var(--color-base-content, inherit);
border-radius: var(--radius-box, 0.5rem);
}
h2 {
color: var(--color-primary, inherit);
}
Commonly used variables (each theme defines light and dark values):
| Variable | Purpose |
|---|---|
--color-base-100 / --color-base-200 / --color-base-300 |
Surface backgrounds, lightest to strongest |
--color-base-content |
Default text color on base surfaces |
--color-primary / --color-primary-content |
Brand color and text on it |
--color-secondary, --color-accent, --color-neutral |
Additional palette roles (each with -content pair) |
--color-info, --color-success, --color-warning, --color-error |
Status colors (each with -content pair) |
--radius-box, --radius-field, --radius-selector |
Corner radii for cards, inputs, small controls |
Reacting to light/dark in logic
If your component needs to know the mode (not just restyle), subscribe:
client.onTheme((theme) => {
console.log(theme.name, theme.dark); // e.g. "slate-teal-dark", true
});
The dev harness ships a dark-mode toggle so you can verify both modes locally —
npm run dev in any sample workspace.
Related
- Building Web Components — the authoring guide
- Security model — why stylesheets are adopted, not fetched