Theming the launcher

The bubble on this page is 72px and sits 32px from the corner, against defaults of 56px and 18px. Nothing was passed to createAiChatWidget to do that — it is four custom properties in the page's own stylesheet.

Plain CSS wins because the widget declares its defaults inside :where(), which has zero specificity. Any rule you write beats them, and you do not need !important or a more specific selector. (The theme option still works and takes precedence, since it writes inline styles.)

.sgiant-aiw-bubble {
  --aiw-launcher-size: 72px;
  --aiw-launcher-offset: 32px;
  --aiw-launcher-icon: 34px;
  --aiw-launcher-offset-sm: 24px;  /* below 480px */
}

The full set: size, offset, offset-sm (below 480px), icon, pill-height, pill-icon, parked-size, parked-icon, dot, dot-sm — each prefixed --aiw-launcher-. The -sm pair applies below 480px and is deliberately independent, so a bigger desktop launcher does not force a bigger phone one.

Whole-theme presets

Every colour is a custom property too. These four are complete themes — click one and the widget repaints live. Open the bubble first.

Each preset is just a map of token names to values. Pass it as the theme option at construction, or write the same properties into a stylesheet — which is what these buttons do, injecting one <style> rule:

createAiChatWidget({
  endpoint: "/chat",
  theme: {
    accent: "#e07a5f",
    "header-bg": "#3d405b",
    "header-fg": "#f4f1de",
    surface: "#fffcf7",
    bg: "#f4f1de",
    text: "#2b2b2b",
    border: "#e4ded1",
  },
});

Precedence, and it matters: the theme and accent options write inline styles, so they beat every stylesheet — yours included. A CSS rule beats only the widget's own defaults, which sit inside :where() and have zero specificity. So pick one mechanism: pass a theme at construction or drive it from CSS. This page uses CSS only — it passes no accent, which is why the buttons above can change one.

Your own brand mark

The mark below is an inline SVG passed as avatarSvg. It stays crisp at any launcher size, which an <img> cannot do, and it costs no network round trip — the bubble looks like itself on the first paint.

Two ways to colour it, and they are a real choice. Use fill="currentColor" and the mark follows the widget's theme, which is right for a monochrome glyph. Give it its own fills or a gradient — as this one does — and it stays your brand's colours under every theme above. The widget draws your mark in both the launcher and the header and makes the ids inside each copy unique, so a gradient works in both — it did not until 2026-09-03, when the second copy resolved url(#g) into the first, which is display:none while the panel is open, and the mark rendered as an empty shape. Ids are still global to the page, so prefix yours if the host has its own SVG defs.

createAiChatWidget({
  endpoint: "/chat",
  avatarSvg: `<svg viewBox="0 0 24 24" fill="none">…</svg>`,
});