Theming the widget
The widget renders inside a Shadow DOM and is neutral by default — restrained light
neutrals, your page’s spacing rhythm, no imposed brand. You theme it with a small set of
CSS custom properties prefixed --bw-*, set on the embed element. Custom properties
inherit across the shadow boundary, so plain CSS on your page is the whole mechanism — no
JavaScript theming API, no rebuild.
The contract
Every variable the widget reads, with its default:
[data-booking-widget] {
/* surfaces */
--bw-bg: oklch(0.995 0.003 230); /* widget background */
--bw-surface: oklch(0.99 0.003 230); /* cards / inputs */
--bw-soft: oklch(0.97 0.004 230); /* soft fills (info cards, rows) */
/* text */
--bw-ink: oklch(0.27 0.012 250); /* primary text */
--bw-muted: oklch(0.53 0.012 250); /* secondary text */
--bw-line: oklch(0.90 0.006 250); /* borders / dividers */
/* brand */
--bw-brand: var(--bw-ink); /* CTA / accent — neutral until set */
--bw-brand-fg: oklch(0.99 0.005 250); /* text on the brand color */
/* semantic (rarely overridden) */
--bw-good: oklch(0.51 0.12 150); /* money-positive ("$0 fee", "paid") */
--bw-warn-bg: oklch(0.96 0.035 75);
--bw-warn-ink: oklch(0.47 0.10 60);
--bw-danger: oklch(0.55 0.18 27);
/* shape & type */
--bw-radius: 14px;
--bw-font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
--bw-shadow: 0 1px 3px oklch(0.2 0.02 250 / 0.10);
/* platform flourish — off by default */
--bw-flash: none; /* the platform's own theme sets this */
/* color scheme */
--bw-scheme: light; /* light | dark | auto */
}
Values are shown in oklch() but any CSS color works — hex, rgb(), whatever your design
system already uses.
Match my brand — a worked example
Say your site is a deep harbor blue with Inter and squarer corners. One rule:
[data-booking-widget] {
--bw-brand: #0b5c8a; /* your accent — buttons, focus, selected states */
--bw-brand-fg: #ffffff; /* readable text on it */
--bw-font: "Inter", system-ui, sans-serif;
--bw-radius: 8px;
}
Setting --bw-brand is the single change that makes the widget feel native to your site;
everything else has a sensible neutral default.
Dark host pages
Set --bw-scheme and the widget switches to its built-in dark palette:
[data-booking-widget] {
--bw-scheme: dark; /* or `auto` to follow the visitor's prefers-color-scheme */
}
The dark palette keeps the same neutral-guest posture (and the same AA contrast bars) as
light. Any --bw-* value you set yourself still wins over the scheme’s defaults, so you can
also hand-tune surfaces instead:
[data-booking-widget] {
--bw-bg: #0f1722; /* dark host page */
--bw-surface: #16202e;
--bw-soft: #1b2636;
--bw-ink: #e8eef5;
--bw-muted: #9fb0c2;
--bw-line: #2a3646;
}
Rules the widget keeps for itself
- Money green stays green. Positive financial state — the
$0 booking feeline, “paid” badges — always renders in--bw-good, never your brand color, so the trust cues stay consistent for anglers across every charter site. - Warnings and errors keep their semantics. Override
--bw-warn-*/--bw-dangeronly to adjust tone, not meaning. - The widget never imports fonts.
--bw-fontis a font-family stack; if you name a webfont, your page loads it (the widget inherits what’s there). - No layout variables. Width, spacing, and structure are fixed for reliability across hosts; the widget fills its container up to its max width.
Scoping
The selector is up to you — anything that matches the mount element works:
/* one widget */
#book-a-trip { --bw-brand: #0b5c8a; }
/* every widget on the site */
[data-booking-widget] { --bw-brand: #0b5c8a; }
Because custom properties inherit, you can also set them on body to theme all embeds at
once — the widget’s internal styles are isolated by the shadow root, but the --bw-*
variables pass through.