Style the widget's chrome
read as.mdThe embed script renders three things into your page: the launcher bubble (or the ask bar, with layout: "bar"), the panel that holds the conversation, and the cold-open shell that shows while the conversation loads. Because they are your page’s DOM, your stylesheet reaches them — and the names below are a promise: they are pinned by a test, so a release cannot rename them under you.
The conversation itself renders inside a frame by default. Its look comes from the app’s chat theme, not from CSS on your page. The exception is an inline mount (layout: "bar", transcript: "inline"): the conversation then lives in your page’s DOM behind a shadow root, and your stylesheet reaches it through a second contract, the transcript’s parts (below).
Class names
Section titled “Class names”| Class | What it is |
|---|---|
guuey-widget |
The root. Modifier classes: guuey-widget--open (panel open), guuey-widget--left (position: "left"), guuey-widget--bar (layout: "bar"), guuey-widget--expanded (the page asked for the full-height overlay), guuey-widget--hidden (guuey("hide")), guuey-widget--glass (the app’s chat theme states shape.glass — the panel and bar are translucent over your page, blurred behind). |
guuey-widget-launcher |
The bubble. guuey-widget-launcher-label is the pill’s text (shape: "pill"). |
guuey-widget-panel |
The panel above the bubble or bar. guuey-widget-frame is the frame inside it. |
guuey-widget-bar |
The ask bar (layout: "bar"): guuey-widget-bar-input and guuey-widget-bar-send. |
guuey-widget-shell |
The cold-open shell shown over the panel until the conversation is ready. |
guuey-widget-scrim |
The fullscreen frosted layer under the expanded panels (only under guuey-widget--expanded, desktop widths): the page shows through the gap between the two panels blurred and tinted, never crisp. It takes no click — Escape or a click on the gap dismisses the takeover. |
guuey-widget-transcript |
The panel when the transcript is mounted inline (transcript: "inline"): the shadow host your ::part() rules hang off (see below). |
Custom properties
Section titled “Custom properties”The loader never writes colours inline. It sets these custom properties on the root and the injected stylesheet reads them — so a rule of yours wins. The two glass properties come from the resolved theme, so they are set from the first paint: frosted (0.82 / 14px) unless the app’s chat theme states its own shape.glass; a theme that states { "opacity": 1 } switches glass off — the guuey-widget--glass modifier comes off, both properties are cleared, and the panel paints opaque. The root also carries an inline color-scheme equal to the effective mode — it keeps the frame’s transparency honest across light and dark, and it is part of the paint, not the contract.
| Property | Paints |
|---|---|
--guuey-widget-canvas |
The panel, shell and bar fill — the app theme’s canvas for the effective mode. |
--guuey-widget-ink |
Text on that fill (the shell’s, the bar’s). |
--guuey-widget-accent |
The launcher bubble’s fill — the color init option. |
--guuey-widget-accent-ink |
The launcher icon and the pill label — the iconColor init option. |
--guuey-widget-glass |
Under guuey-widget--glass: the panel’s and bar’s fill alpha, a number 0–1 (the theme’s shape.glass.opacity; 1 is opaque). |
--guuey-widget-blur |
Under guuey-widget--glass: the backdrop blur behind the panel and bar, a length (the theme’s shape.glass.blur; 14px when unset). |
--guuey-widget-shadow |
The panel’s and bar’s box-shadow — one value composed from the theme’s shape.shadow (colour at its intensity); frosted glass with a soft shadow is the default. |
--guuey-widget-scrim-tint |
The expanded scrim’s colour — the theme’s scrim.tone (#fff / #000) when stated, else your page’s own ground (read from body), else the panel canvas. |
--guuey-widget-scrim-opacity |
The scrim’s alpha, a number 0–1 (the theme’s scrim.opacity; 0.45 when unset). Where backdrop-filter is unsupported the tint alone frosts, at twice this alpha. |
--guuey-widget-scrim-blur |
The blur of the page behind the scrim, a length (the theme’s scrim.blur; 14px when unset). |
--guuey-widget-radius-scale |
A bare multiplier on the panel’s own radii (16px; the ask-bar panel’s 24px; the phone sheet’s top corners) from the theme’s shape.radius — none 0, soft 1, round 1.5 — or, for an app with no theme, your page’s own card radius. The bubble and the ask-bar pill keep their shapes. |
--guuey-widget-font |
The family of the cold-open shell, the ask bar and the pill label — the theme’s typography.fontFamily, else your page’s body family, else system-ui, sans-serif. |
--guuey-widget-motion-duration |
The open/close fade length of the panel, the cold-open shell and the backdrop — the theme’s motion.duration.base (a CSS time), else 180ms. The loader keeps the panel mounted for the same time on close, so a longer fade is never cut. |
--guuey-widget-motion-easing |
The easing of those fades — the theme’s motion.easing.standard, else ease-out. Under prefers-reduced-motion: reduce there is no transition at all, whatever these say. |
Example
Section titled “Example”/* Square corners on the bar, your brand on the bubble, your own fill everywhere */.guuey-widget { --guuey-widget-canvas: #fffdf7; --guuey-widget-ink: #1a1a1a;}.guuey-widget-launcher { --guuey-widget-accent: #0b5cff; --guuey-widget-accent-ink: #fff;}.guuey-widget-bar { border-radius: 8px; box-shadow: none; border: 2px solid #1a1a1a;}.guuey-widget-panel { border-radius: 8px;}Style the transcript
Section titled “Style the transcript”With layout: "bar" and transcript: "inline", the conversation is mounted in your page, inside a shadow root on the panel. It is the same chat kit guuey.com runs. Your CSS cannot reach the kit’s own classes (that isolation is the point), but the kit exposes its structural elements as CSS Shadow Parts, and those names are a contract: added, never renamed or removed.
| Part | Element |
|---|---|
surface |
The kit’s outer surface, where the app theme is stamped. |
header |
The header row (the launcher label and the close button). |
transcript |
The scrolling transcript. |
message, message user, message agent |
Every message; the visitor’s bubble; the agent’s text. |
narration |
The agent’s interim status line while it works. It is not a message, so your message rules leave it alone. |
composer, composer-input, composer-send, composer-stop |
The kit’s own composer. It is absent in the bar layout, where the bar is the input. |
chips, chip |
The suggestion row and each chip. |
thread-closed |
The banner shown when the agent has ended the conversation. |
/* Your brand on the visitor's bubbles, a quieter header, host fonts throughout */.guuey-widget-transcript::part(message user) { background: #0b5cff; color: #fff; border-radius: 12px 12px 4px 12px;}.guuey-widget-transcript::part(header) { font-weight: 600; font-size: 14px; border-bottom: 0;}.guuey-widget-transcript::part(surface) { font-family: inherit;}Two things stay as they were: the transcript’s colors and type still come from the app’s chat theme unless a part rule of yours overrides them, and generated cards still render in their own frames. A card never becomes your page’s DOM, so card styling stays with the theme.
Two rules
Section titled “Two rules”- Your CSS lives on your page. The widget never accepts a stylesheet or a CSS string — that would be a door into an origin that is not yours. Restyle the contract classes from your own stylesheet.
- Everything else may change. Badges, the backdrop, the shell’s inner rows and the panel’s own open/show state classes (
guuey-widget-panel--open,guuey-widget-panel--show) are not in the contract — the root’sguuey-widget--openmodifier above is. Style the names above; the rest is ours to move.