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.
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.
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>`,
});