Appearance
You pick one colour. Everything else — the header, the visitor’s bubbles, the send button, the launcher, the unread badge, the focus rings — is derived from it, in both light and dark mode, with contrast checked rather than hoped for.
Where these live#
All of it is dashboard configuration: Websites → your site → Widget. There is no appearance API on the page — a visitor-specific colour would defeat the cache that lets the launcher paint in your brand before the widget has even loaded. Changes reach every visitor on their next page load.
The settings#
- Accent colour#rrggbb · default #234e3a
- The one brand input. Six-digit hex only — three-digit shorthand, named colours,
rgb(), and anything with transparency are rejected, and an unparseable value falls back to Normalize green rather than rendering something broken. - Theme'light' | 'dark' | 'auto' · default 'light'
- The surface family the chat window sits on.
autofollows the visitor’s own system setting. See Light, dark, auto. - Position'left' | 'right' · default 'right'
- Which bottom corner the launcher sits in. The unread badge, the docked chat card, and the message toast all follow it to the same side.
- Launcher icon'chat' | 'chats' | 'question' | 'lifebuoy' · default 'chat'
- The glyph on the closed launcher. Four Phosphor icons, drawn into the button at build time. See The launcher for when it is not shown at all.
- Team nametext, ≤ 120 chars · default “Support”
- Who the visitor is talking to when nobody in particular is online. Shown in the chat header in place of an agent’s name.
- Welcome texttext, ≤ 280 chars · default “Hi there 👋 How can we help?”
- The line under the header on the widget’s home view. This is chrome, not a message — for the greeting that appears in the thread itself, see Messages.
How one colour becomes a palette#
Your accent is run through a single derivation that produces eleven values, and every surface in the widget reads one of them. Nothing anywhere hardcodes a colour, which is why the launcher, the chat window, and the live preview in the dashboard can never drift apart.
- The accent itself paints the launcher, the visitor’s own message bubbles, and the send button.
- A deep shade of it becomes the panel used by the header, the home call-to-action, and the unread badge — which is why the badge stays visible sitting on top of the accent circle.
- Text on those surfaces is chosen by measuring luminance, so a pale yellow accent gets near-black text and a navy one gets white. You cannot pick a colour that makes the widget unreadable.
- The accent used as text — links, chips, focus rings — is nudged darker in light mode and lighter in dark mode until it clears WCAG AA against the surface behind it. It is often not the same hex you typed, and that is deliberate.
- The surfaces themselves stay brand-neutral: clean white and grey in light mode, near-black in dark. The widget sits on your website, so the ground stays yours.
Light, dark, auto#
auto resolves against the visitor’s prefers-color-scheme, and it keeps resolving: a visitor who flips their system to dark with the chat open sees the window follow immediately, without a reload.
Only the surfaces change between modes. The accent, its deep shade, and the text colours placed on them are mode-independent — which is what lets the launcher paint correctly from cache before the widget has worked out which mode it is in.
Pick from where the widget will be seen rather than from taste. A dark widget on a white marketing site reads as a foreign object; on a dark product UI, a white one does.
The launcher#
A 56-pixel circle in a shadow root, so your CSS cannot reach it and its CSS cannot reach your page. It shows, in order of preference:
- A close cross, when the chat is open.
- The available agent’s avatar, when someone on your team is online — so a visitor sees who is there before they open anything. If the image fails to load it falls back to the icon.
- Your chosen launcher icon otherwise.
The unread badge sits on the corner nearest the screen edge and counts up to 99+. While the tab is in the background and something is unread, the page title flickers between your title and (n) New message every 1.5 seconds, and restores your exact title — including one your own app rewrote mid-flicker — as soon as the tab is looked at again.
Size and placement#
Not configurable, and worth knowing before you plan a page layout around it.
- Launcher56 × 56 px · 20 px from the bottom and the chosen side
- Rendered at a z-index just below the chat window’s.
- Chat window, desktop384 px wide · up to 640 px tall
- Docked 88 px above the bottom, on the chosen side. Height shrinks to fit short windows.
- Chat window, mobilefull screen
- Used below 480 px wide, and on touch devices under 600 px tall — which is what a phone in landscape is. Sized to the visual viewport rather than
100vh, so the composer stays above the on-screen keyboard instead of behind it. - Message toast340 × 96 px desktop · full width on mobile
- The preview card that appears above the launcher when a reply arrives with the chat closed. Drawn inside the iframe, so the message text never reaches your page.
You can hide the launcher entirely on chosen pages from your own JavaScript — see Hide the widget on some pages.
Not adjustable#
Honest list, so you do not spend an afternoon looking. None of these have a setting today:
- Launcher size, offsets, corner radius, and shadow.
- Fonts inside the widget. It uses the visitor’s system UI font.
- Custom CSS or a stylesheet override. The shadow root and the cross-origin iframe both exist precisely to make that impossible in either direction.
- Copy other than the team name and the welcome line.
What visitors can change#
One thing: the notification chime, toggled inside the widget and remembered in their own browser. Their choice overrides nothing else, and it does not reach your dashboard.