Widget reference
Props, attributes, DOM events and CSS custom properties of HelpdeskWidget, HelpdeskConversations, their custom elements and the script tag.
The widget is the customer side of the helpdesk. It comes in two forms over the same widget/* routes:
| Form | React | Custom element | Registers it |
|---|---|---|---|
| A launcher and a floating panel | HelpdeskWidget | <helpdesk-widget> | defineHelpdeskWidget() |
| The panel in the page, always open, without a launcher | HelpdeskConversations | <helpdesk-conversations> | defineHelpdeskConversations() |
All four exports come from better-helpdesk/widget, which starts with 'use client'. Each element renders into its own open shadow root, so the host's styles do not reach it. Related guides: Add the widget, Add a support page, Theme the widget and the agent UI.
React props
HelpdeskWidget takes every prop below. HelpdeskConversations takes all but label.
Prop
Type
import { HelpdeskWidget } from 'better-helpdesk/widget';
<HelpdeskWidget inbox="support" locale="en" context={{ plan: 'team' }} />Element attributes
<helpdesk-widget> and <helpdesk-conversations> read the same values as attributes. A changed attribute takes effect at once.
| Attribute | Prop | Value |
|---|---|---|
api | api | URL |
inbox | inbox | Inbox key |
locale | locale | en, de, fr, it, or a browser language tag |
types | types | Comma-separated list |
org | orgId | Organization id |
identity-token | identityToken | JWT |
app-version | appVersion | String |
label | label | String, <helpdesk-widget> only |
theme | none | auto follows the operating system's dark mode. The React wrappers take it as the theme prop. |
The context property, not an attribute, carries the host context: element.context = { plan: 'team' }.
import { defineHelpdeskWidget } from 'better-helpdesk/widget';
defineHelpdeskWidget();defineHelpdeskWidget(tag = 'helpdesk-widget') and defineHelpdeskConversations(tag = 'helpdesk-conversations') register the elements under another tag name when given one. Each does nothing on the server or when the tag is already registered.
Script tag
widget.js in the published package (better-helpdesk/widget.js, the file dist/widget.js) is a standalone build with React included. The handler does not serve it: the host serves the file itself, in the example below from the root of its site (Add the widget copies it into public/). The script registers <helpdesk-widget>, then appends one to document.body with an attribute for each data-* attribute of the script tag: data-api becomes api, data-identity-token becomes identity-token, data-theme becomes theme.
<script
src="https://app.example.com/widget.js"
data-api="https://app.example.com/api/helpdesk"
data-inbox="sales"
data-locale="de"
async
></script>Only the element the script creates comes alive. A <helpdesk-widget> already in the page's markup stays inert. Loading the script again while its widget is still in the page adds no second one.
Element methods
| Method | What it does |
|---|---|
open({ type?, subject?, message? }) | Opens the panel. With type, such as 'bug', it opens on that type's form when the inbox offers it, and on its first view otherwise; focus moves into the form. subject and message go into the form's fields the customer has left empty, and the customer can change them before sending; the subject field shows on bug, feature and question forms. On a panel that is already open, it keeps a draft the customer is writing unless type names another form, and it never leaves a conversation the customer is replying in. |
<helpdesk-widget> and <helpdesk-conversations> both have it. Code that holds the element calls it directly, for example from a button of the host's own:
document.querySelector('helpdesk-widget')?.open({
type: 'bug',
message: 'The export button did nothing.',
});With the React wrapper, pass a ref:
import { HelpdeskWidget, type HelpdeskWidgetElement } from 'better-helpdesk/widget';
import { useRef } from 'react';
const widget = useRef<HelpdeskWidgetElement>(null);
// <HelpdeskWidget ref={widget} />
// later: widget.current?.open({ type: 'bug' });HelpdeskWidgetElement is the element's type and OpenRequest the options of open(); the package also registers both tags with TypeScript, so document.querySelector('helpdesk-widget') is typed without a cast.
DOM events
The element dispatches these on itself. They bubble and cross the shadow boundary.
| Event | detail | When |
|---|---|---|
helpdesk:open | none | The panel opens. <helpdesk-widget> only. |
helpdesk:message-sent | { inbox: string, type: string, segment?: string, reference: string } | A new conversation is sent. |
helpdesk:booking-clicked | { reference: string } | The customer follows the booking link. |
document.addEventListener('helpdesk:message-sent', event => {
const { reference } = (event as CustomEvent<{ reference: string }>).detail;
});Key presses in the widget's text fields stop at the element, so they do not reach the host page's shortcuts.
What the widget captures
A message sent with Send us a message is a chat and carries the page URL and locale. A ticket for a bug, feature or question is a ticket, and its context holds the page URL and title, user agent, viewport, locale, appVersion, the last 10 errors and unhandled rejections on the page (300 characters each), and the host context as host. The form lists each item, and the customer can leave any of them out. On an inbox with priorities, a ticket form also asks a signed-in customer of a tier the inbox offers them to to pick one, named by priorityLabels and explained by the inbox's text; a visitor is never asked. Once sent, the thread says by when the team aims to reply when the conversation falls under a response target, and after resolution asks for a rating: good or bad, or 1 to 5 with ratingScale: 5. For any other type, it holds the page URL, the locale, the first page of the visit, the external referrer and the UTM parameters of that first page. The fields and their limits are on HTTP routes.
Browser storage
| Key | Storage | Holds |
|---|---|---|
helpdesk-visitor:{api} | localStorage | An anonymous visitor's token, per API base URL without its trailing slash. |
helpdesk-visitor | localStorage | Read when the key above is empty; written by earlier versions. |
helpdesk-landing | sessionStorage | The first page of the visit. |
helpdesk-referrer | sessionStorage | The external referrer of the visit, or an empty string. |
helpdesk-searches:{api} | localStorage | The last five documentation searches, shown on Home. |
CSS custom properties
Set on the element or any ancestor; the values inherit into the shadow root.
| Property | Default | Styles |
|---|---|---|
--helpdesk-font | system-ui, -apple-system, 'Segoe UI', sans-serif | Font family |
--helpdesk-bg | #ffffff | Panel background |
--helpdesk-fg | #0c2034 | Text; shadows are tinted from it |
--helpdesk-muted | #486581 | Secondary text |
--helpdesk-border | #d9e2ec | Borders |
--helpdesk-subtle | #f0f4f8 | Quiet backgrounds |
--helpdesk-accent | #0c2034 | Buttons, links, unread dots |
--helpdesk-accent-hover | #243b53 | Accent on hover |
--helpdesk-accent-fg | #f0f4f8 | Text on the accent |
--helpdesk-danger | #cf1124 | Errors |
--helpdesk-focus | #f55068 | Focus ring |
--helpdesk-radius | 12px | Corners; controls step down from it and dialogs step up |
--helpdesk-launcher-bg | the accent | Launcher background |
--helpdesk-launcher-fg | the accent foreground | Launcher icon and label |
--helpdesk-panel-header-bg | the accent | Panel header background |
--helpdesk-panel-header-fg | the accent foreground | Panel header text |
--helpdesk-panel-border | 1px solid the border color | Panel border |
--helpdesk-shadow | a soft shadow tinted from the text color | Shadows of the launcher, the panel and pop-ups; none removes them |
--helpdesk-offset-bottom | 20px | Distance of the widget from the bottom of the viewport |
--helpdesk-page-height | 640px | Height of <helpdesk-conversations> |
With theme="auto" and a dark operating system theme, unset properties take dark defaults: background #102a43, text #f0f4f8, muted #bcccdc, border #334e68, subtle #243b53, accent #f0f4f8, accent hover #d9e2ec, accent foreground #0c2034, panel header #243b53 on #f0f4f8.
The agent UI reads most of the same properties; see Agent UI.