Bubble Customization
The bubble's appearance is fully customizable through HTML attributes, CSS custom properties, and custom launcher elements.
CSS Custom Properties
Override these properties on the <saytv-chat-bubble> element to fine-tune the appearance beyond what attributes offer.
| Property | Default | Description |
|---|---|---|
--stv-bubble-size | 60px | Launcher button diameter. Prefer the bubble-size attribute. |
--stv-bubble-color | #7e171c | Launcher background color. Prefer the bubble-color attribute. |
--stv-bubble-offset-x | 24px | Horizontal offset from viewport edge. |
--stv-bubble-offset-y | 24px | Vertical offset from viewport edge. |
--stv-bubble-z-index | 999999 | Stacking order. |
--stv-bubble-panel-width | 350px | Chat panel width. |
--stv-bubble-panel-height | 600px | Chat panel height. |
--stv-bubble-panel-radius | 16px | Chat panel border radius. |
--stv-bubble-gap | 16px | Space between the launcher and the panel/greeting. |
Example
saytv-chat-bubble {
--stv-bubble-panel-radius: 24px;
--stv-bubble-gap: 20px;
--stv-bubble-z-index: 500;
}TIP
Attributes like bubble-size, bubble-color, offset-x, offset-y, chat-width, and chat-height set these CSS properties automatically. Use custom properties directly only when you need values not covered by attributes (like --stv-bubble-panel-radius or --stv-bubble-gap).
Custom Launcher
Replace the built-in circular button with any element on your page using the custom-launcher attribute:
<button id="my-chat-button" class="my-custom-launcher">
💬 Chat with us
</button>
<saytv-chat-bubble
app-id="your-app-id"
custom-launcher="#my-chat-button"
></saytv-chat-bubble>When custom-launcher is set:
- The built-in launcher button is hidden
- Click events on the referenced element toggle the chat panel
- You have full control over the trigger's appearance, position, and behavior
- The chat panel still appears at the bubble element's position
Positioning the panel with a custom launcher
The panel is positioned relative to the bubble element, not the custom launcher. If your custom launcher is in a different location, adjust the bubble's offset to align the panel:
<saytv-chat-bubble
app-id="your-app-id"
custom-launcher="#my-header-button"
position="bottom-right"
offset-x="20"
offset-y="20"
></saytv-chat-bubble>Custom Launcher Icon
Replace the default chat icon with a custom image while keeping the built-in launcher button:
<saytv-chat-bubble
app-id="your-app-id"
bubble-icon="https://cdn.example.com/my-icon.png"
></saytv-chat-bubble>The image is displayed as a 32px circle inside the launcher. When the panel is open, the icon morphs to a close (X) icon.
Theming the Inner Widget
The inner <saytv-chat> widget inherits the theme attribute from the bubble. You can also pass CSS custom properties to style the widget through the bubble:
<saytv-chat-bubble
app-id="your-app-id"
theme="dark"
style="--stv-color-primary: #0066cc; --stv-color-accent: #00cc66;"
></saytv-chat-bubble>All <saytv-chat> theming variables work. See the Theming guide for the full list.
Animations
The bubble uses CSS transitions for all animations:
| Animation | Duration | Easing |
|---|---|---|
| Launcher hover scale | 150ms | ease |
| Launcher active press | 150ms | ease |
| Icon morph (chat ↔ close) | 300ms | cubic-bezier(0.4, 0, 0.2, 1) |
| Panel open (slide up + scale) | 300ms | cubic-bezier(0.4, 0, 0.2, 1) |
| Panel close (slide down + scale) | 200ms | cubic-bezier(0.4, 0, 0.2, 1) |
| Greeting tooltip appear | 300ms | cubic-bezier(0.4, 0, 0.2, 1) |
| Unread badge scale | 200ms | cubic-bezier(0.4, 0, 0.2, 1) |
All animations respect prefers-reduced-motion: reduce. When the user has motion reduction enabled, transition durations are set to 0ms.
Mobile Behavior
On viewports narrower than 768px:
- The chat panel goes full-screen (100% width and height) instead of floating
- The panel slides up from the bottom
- The greeting tooltip is hidden (not useful on small screens)
- The launcher button remains visible for opening/closing
To hide the bubble entirely on mobile, add the hide-on-mobile attribute:
<saytv-chat-bubble
app-id="your-app-id"
hide-on-mobile
></saytv-chat-bubble>Accessibility
The bubble follows WAI-ARIA patterns for disclosure widgets:
- The launcher has
role="button"andaria-expandedreflecting the panel state - The launcher's
aria-labelupdates between "Open chat" and "Close chat" - The panel has
role="dialog"witharia-label="Chat" - The unread badge uses
aria-live="polite"for screen reader announcements - Focus returns to the launcher when the panel closes
- The launcher supports
:focus-visiblestyling - Keyboard:
Escapecloses the panel
Bundle Size
The bubble is a separate entry point from the main widget, keeping its own footprint small:
| Format | Size (gzip) |
|---|---|
ESM (bubble.mjs) | ~5 kB |
IIFE (bubble.iife.js) | ~4 kB |
The inner <saytv-chat> widget is loaded lazily when the user first opens the panel.