iAdvizeDocs

Style engagement widgets with CSS

The supported CSS surface on the chat bubble, the question bar, the inline button and Starters: eight custom properties, nine shadow parts, and what stays private.

The chat bubble, question bar, inline button and Starters render inside a shadow root, so your storefront's CSS can't reach them by accident, and can't restyle them by accident either. Two mechanisms are open on purpose:

  • CSS custom properties: recolour a widget. Use these first.
  • Shadow parts (::part): reach an element directly when a custom property doesn't cover what you need.

Both are written in your own stylesheet. Neither needs a new Content Security Policy directive: the rules are yours, served from your origin, under the style-src you already have. Nothing here replaces the dashboard's appearance fields. Reach for CSS when the structured fields don't express what you want.

The dashboard says Chat bubble, the CSS says launcher

Every identifier on this page (data-iadvize-launcher-host, the --iadvize-launcher-* properties, the launcher parts) keeps the name it shipped with. The dashboard now labels that widget format Chat bubble; nothing in the contract below changed with it, so no stylesheet needs editing.

Only what's listed here is a contract

The names on this page are the whole supported surface. Every other element, attribute, and internal detail of a widget is private and may change without notice, including in a release that carries no changelog entry. Renaming or removing anything listed here is a breaking change and is announced in the changelog.

Host selectors

Every widget the tag renders on a page has a host element you write your rules against. The two floating formats append theirs to <body>; an inline widget's host (the inline button's or Starters' alike) is at its mount point, and which selector reaches it depends on the mount mode:

SelectorElement
[data-iadvize-launcher-host]One per launcher widget rendered here
[data-iadvize-composer-host]One per question bar rendered here
iadvize-widgetAn inline button or a Starters widget mounted as our custom element (no attribute involved)
[data-iadvize-widget-host]An inline button or a Starters widget we mounted ourselves (the marker element and CSS selector modes)

All inline forms share the same host selectors, whichever inline format renders inside them. This is part of the contract, so renaming or removing any of it is a breaking change.

The host carries no widget id, so a rule written against these selectors applies to every widget of that type on the page. If you run two launchers on one site, you can't target one of them from CSS. Configure them separately in the dashboard instead. An inline widget is the one exception in practice: in the custom-element mode you can narrow to a single widget through the slot you chose, iadvize-widget[data-iadvize-slot='product-cta'].

CSS custom properties

Recommended, because they don't depend on the widget's internal structure: if we restructure the DOM later, your rules keep working.

Only colours are exposed. Size, corner radius, and shadow are not themeable this way: set them from the widget's Design card, or reach for a part.

Set a property on the host, or on any ancestor it inherits from (:root, body, a wrapper):

your-storefront.css
[data-iadvize-launcher-host] {
  --iadvize-launcher-bg: #111111;
  --iadvize-launcher-fg: #ffffff;
}

Chat bubble and inline button

PropertyPaints
--iadvize-launcher-bgThe button's background
--iadvize-launcher-fgThe button's text colour (i.e. the optional visible label)

The inline button reuses these, on purpose

There is no --iadvize-button-* set and no button part. An inline button is the chat bubble's control in a different place (a control, an icon and a label), so it carries the same two properties and the same three part names below, and every rule you already wrote against a launcher applies to it unchanged. Set them on iadvize-widget or [data-iadvize-widget-host], or on any ancestor they inherit from.

Question bar

PropertyPaints
--iadvize-composer-bgThe bar's background
--iadvize-composer-fgThe text the shopper types
--iadvize-composer-accentThe send button's circle
--iadvize-composer-accent-fgThe arrow glyph inside the send button

Starters

Starters reuses both sets: no `--iadvize-starters-*` property

Starters is a composite widget: an icon+label header, up to three starter-question chips, and a free-text field. It carries no properties of its own: the header takes --iadvize-launcher-bg/-fg (the same tinted-icon-and-label pair a chat bubble uses), the field takes --iadvize-composer-bg/-fg/-accent/-accent-fg (the same neutral-bar-plus-accented-send-button pair the question bar uses), and the chips take --iadvize-starter-bg/-fg below, same as every other format's chips. Set them on iadvize-widget or [data-iadvize-widget-host], or on any ancestor they inherit from.

Starter questions

The starter-question chips a widget renders above itself. Both formats use the same two properties, set on whichever host the chips belong to.

PropertyPaints
--iadvize-starter-bgA chip's background
--iadvize-starter-fgA chip's text

Unset, a chip inverts its widget's own resolved colours: the widget's foreground becomes the chip's background, and vice versa.

Leave a property unset and the widget renders the value resolved from its dashboard configuration and your site's branding. An unset property changes nothing.

The loader stores these as var() references, so they resolve live. A media query, a dark-mode block, or a runtime setProperty() call all take effect immediately:

your-storefront.css
@media (prefers-color-scheme: dark) {
  [data-iadvize-launcher-host] {
    --iadvize-launcher-bg: #f5f5f5;
    --iadvize-launcher-fg: #111111;
  }
}

The glyph and the label share one colour

The launcher's icon is an inline <svg> whose fill is currentColor, so it follows the same colour as the text label. Setting --iadvize-launcher-fg recolours both, and so does a color declaration on ::part(launcher). There is no separate property for the glyph on its own.

Shadow parts

Nine elements carry a part name. Nothing else does.

PartElement
launcherThe <button>: a chat bubble's, or an inline button's
launcher-iconThe <svg> glyph: inside the launcher button, or inside Starters' non-interactive header
launcher-labelThe <span> holding the label (optional on a bubble, required on an inline button and on Starters)
composerThe question bar itself, or Starters' free-text field's own wrapper
composer-inputThe text field a shopper types in
composer-sendThe send button
startersStarters' own host wrapper, selecting the whole widget
starter-questionsThe column wrapping a widget's starter-question chips
starter-questionOne chip's <button>

On Starters, `launcher-icon`/`launcher-label` are not a button

Reusing these two part names does not mean Starters' icon+label header is clickable. Unlike the chat bubble and the inline button, it is plain, non-interactive markup: no click handler, no keyboard focus stop, no :focus-visible ring. Only the chips and the free-text field open the conversation. The names are reused because Shadow Parts select by attribute, not by the underlying element's interactivity, and the visual role (an icon beside a line of text) is the same one.

your-storefront.css
[data-iadvize-launcher-host]::part(launcher) {
  box-shadow: none;
  border: 2px solid #111111;
}

/* The same three parts reach an inline button. */
iadvize-widget[data-iadvize-slot='product-cta']::part(launcher) {
  border-radius: 4px;
}

[data-iadvize-launcher-host]::part(launcher-label) {
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

[data-iadvize-composer-host]::part(composer-send) {
  border-radius: 8px;
}

A ::part() rule from your stylesheet beats the inline styles the loader applies, so you don't need !important to override a property we already set. The loader sets box-shadow, border, and border-radius itself, and all three examples above still take effect as written.

Two limits are worth knowing before you build on parts:

  • A part freezes internal structure. These eight names are a public API we're committed to, but the elements around them aren't. Prefer a custom property when one covers your case.
  • You can't select inside a part. ::part() accepts pseudo-classes (::part(launcher):hover works) but not descendant selectors: there's no way to reach an element nested inside a named part.

The label inherits your page's font, on both the chat bubble and the inline button, because a shadow root inherits inheritable properties from its host. That's the default with no CSS from you; setting font-family on the host or on ::part(launcher-label) changes it. There is no font field in the dashboard and the tag requests no font file, so this stylesheet is the only place a face is chosen.

One thing you can only do here, and it matters for an inline button: reserve its space, so nothing on the page moves when it appears. See Reserve the space.

What this surface doesn't cover

  • The conversation panel and everything inside it. The conversation runs in a cross-origin iframe, which your CSS cannot style at all. Its colours, font, and logo come from Site → Settings → Branding. See Branding.
  • Geometry, via custom properties. There is no custom property for size, corner radius, or shadow. Use the widget's Design card, or a ::part(launcher) / ::part(composer) rule.
  • The page-side override. iadvize('set', { launcher: … }) accepts enabled, offsetBottom, and offsetSide only. There is no page-side way to change a widget's appearance from JavaScript: that's the dashboard's job, or this stylesheet's.
  • The AI-transparency disclosure. Every control's accessible name and title always carry it (the chat bubble's and the inline button's alike), and so does every starter-question chip's accessible name. No CSS you write, and no field you set, removes it.

On this page