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, with no JavaScript theming API and 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:      inherit;                /* default: use your page's font       */
  --bw-font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
                                           /* money amounts + booking references  */
  --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:   auto;                    /* auto (default) | light | dark      */
}

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

By default the widget follows your visitor’s OS setting: --bw-scheme ships as auto, so on a device set to dark the widget renders dark, and on light it renders light, with no configuration needed. It stays a neutral guest and never imposes a theme on your page.

To pin the scheme regardless of the visitor’s OS, set --bw-scheme explicitly:

[data-booking-widget] {
  --bw-scheme: dark;    /* force dark — or `light` to force light, or `auto` (the default) */
}

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 fee line, “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-danger only to adjust tone, not meaning.
  • The widget never imports fonts. --bw-font is 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.