Skip to content

Bubble API & Events

The <saytv-chat-bubble> element exposes a JavaScript API for programmatic control and dispatches custom events for integration with your application.

JavaScript API

Access the bubble element and call methods directly:

js
const bubble = document.querySelector('saytv-chat-bubble');

Methods

MethodDescription
open()Open the chat panel. Creates the inner widget on first call.
close()Close the chat panel with a closing animation.
toggle()Toggle the panel open/closed.
show()Show the bubble (after it was hidden).
hide()Hide the entire bubble (launcher + panel). Closes the panel first if open.
destroy()Full teardown - removes the inner widget, clears timers, and removes event listeners.
setUsername(name)Rename the signed-in user. Returns a Promise<User>.

Properties

PropertyDescription
translations (setter)Supply translation catalogs keyed by locale. Registered globally, so the launcher's own chrome (tooltip, aria-labels) is localized too, and forwarded to the inner widget.
js
bubble.translations = {
  fr: { 'bubble.openChat': 'Ouvrir la discussion' },
};

Unlike <saytv-chat>, the bubble renders chrome of its own before the widget exists, which is why setting this on the bubble covers both. For a hosted catalog use the translations-url attribute instead. See Localization.

open()

Opens the chat panel. If this is the first time opening, the inner <saytv-chat> widget is created and mounted. Subsequent calls show the existing widget without re-creating it.

js
bubble.open();

The greeting tooltip is automatically dismissed when the panel opens. The unread badge is reset to zero.

close()

Closes the chat panel with a slide-down animation (200ms). Focus returns to the launcher button.

js
bubble.close();

toggle()

Convenience method that opens the panel if closed, or closes it if open.

js
bubble.toggle();

show() / hide()

Control the visibility of the entire bubble element. hide() closes the panel first if it's open.

js
// Hide the bubble when user navigates to a page where chat isn't needed
bubble.hide();

// Show it again
bubble.show();

Internally, hide() sets the hidden attribute and show() removes it.

setUsername()

Renames the signed-in user. Available on both <saytv-chat-bubble> and <saytv-chat> — see Methods for the full reference.

js
try {
  const user = await bubble.setUsername('new-name');
  console.log('Renamed to', user.username);
} catch (err) {
  // err.errors.username explains why: taken, too short, or blocked by moderation
  console.error(err.errors?.username?.[0] ?? err.message);
}

The JWT username claim is applied when the account is first created, and re-authenticating with a changed claim syncs it. Use this method when your app lets users rename themselves mid-session, or when you need to handle the rejection reason yourself.

Usernames must be at least 3 characters, unique across the tenant, and pass moderation. A name held by a deleted account is released and can be reused.

WARNING

Guests cannot rename themselves. Calling this on a guest session rejects with a 403.

destroy()

Tears down the bubble completely. Removes the inner widget, clears greeting and animation timers, and removes all event listeners (keyboard, outside click, mobile detection).

js
bubble.destroy();

WARNING

After calling destroy(), the bubble element remains in the DOM but is inert. Remove it from the DOM if you no longer need it:

js
bubble.destroy();
bubble.remove();

Events

The bubble dispatches its own events prefixed with saytv:. These are standard CustomEvent objects that bubble up through the DOM.

EventFired WhenDetail
saytv:openChat panel opens-
saytv:closeChat panel closes-
saytv:readyInner <saytv-chat> widget fires stv:ready-
saytv:unreadUnread message count changes{ count: number }

Listening to Events

js
const bubble = document.querySelector('saytv-chat-bubble');

bubble.addEventListener('saytv:open', () => {
  console.log('Chat opened');
});

bubble.addEventListener('saytv:close', () => {
  console.log('Chat closed');
});

bubble.addEventListener('saytv:ready', () => {
  console.log('Chat widget is ready');
});

bubble.addEventListener('saytv:unread', (e) => {
  console.log('Unread messages:', e.detail.count);
});

Unread Badge

The bubble tracks incoming messages via the inner widget's stv:message-received event. When the panel is closed, each new message increments the unread count and the saytv:unread event fires. When the panel opens, the count resets to zero.

js
bubble.addEventListener('saytv:unread', (e) => {
  // Update your page title or favicon
  document.title = e.detail.count > 0
    ? `(${e.detail.count}) My Site`
    : 'My Site';
});

The badge displays counts up to 99 and shows "99+" for higher values.

Inner Widget Events

All standard <saytv-chat> events (stv:ready, stv:message-sent, stv:user-login, etc.) are dispatched on the inner widget element inside the shadow DOM. They do not automatically propagate to the bubble element.

To listen for inner widget events, use the saytv:ready event to know when the widget exists, then access it:

js
bubble.addEventListener('saytv:ready', () => {
  // The inner widget is now available in the shadow DOM
  const widget = bubble.shadowRoot.querySelector('saytv-chat');

  widget.addEventListener('stv:message-sent', (e) => {
    console.log('Message sent:', e.detail.message);
  });

  widget.addEventListener('stv:user-login', (e) => {
    console.log('User logged in:', e.detail.user);
  });
});

Common Patterns

Open bubble from a custom button

Use the JavaScript API to trigger the bubble from anywhere in your page:

html
<button id="help-btn">Need Help?</button>

<saytv-chat-bubble app-id="your-app-id"></saytv-chat-bubble>

<script>
  document.getElementById('help-btn').addEventListener('click', () => {
    document.querySelector('saytv-chat-bubble').open();
  });
</script>

Hide on specific pages

js
const bubble = document.querySelector('saytv-chat-bubble');

// Hide on checkout pages
if (location.pathname.startsWith('/checkout')) {
  bubble.hide();
}

Analytics integration

js
bubble.addEventListener('saytv:open', () => {
  analytics.track('chat_bubble_opened');
});

bubble.addEventListener('saytv:close', () => {
  analytics.track('chat_bubble_closed');
});

bubble.addEventListener('saytv:unread', (e) => {
  if (e.detail.count > 0) {
    analytics.track('chat_unread_message', { count: e.detail.count });
  }
});

Conditionally show based on user state

js
const bubble = document.querySelector('saytv-chat-bubble');

// Only show for logged-in users
if (!currentUser) {
  bubble.hide();
}

// Show after a delay for first-time visitors
if (isFirstVisit) {
  setTimeout(() => bubble.show(), 10000);
}

SayTV Chat SDK Documentation