Theming
Restyle the widget from the outside with CSS custom properties for colour, ::part() selectors for shape and layout, and named slots for your own markup, plus the side-panel recipe.
Colour is a token, shape is a part, and a region you want to own outright is a
slot. Host-page CSS beats everything the widget resolves at runtime, and no
rule in the widget uses !important. Every table below is rendered from the
descriptor the widget reads.
Theme tokens
CSS custom properties, set on the element or anywhere above it.
deskbell-widget {
--deskbell-accent: #2b6b4f;
--deskbell-radius: 12px;
}| Custom property | Controls |
|---|---|
--deskbell-surface | Panel background |
--deskbell-surface-subtle | Assistant bubbles, pills, chips |
--deskbell-surface-hover | Hover background for rows and buttons |
--deskbell-surface-active | Pressed/active background |
--deskbell-text | Primary text |
--deskbell-text-secondary | Chip and pill text |
--deskbell-text-muted | Secondary text, refusals, empty state |
--deskbell-text-subtle | Timestamps, labels, placeholders |
--deskbell-border | Dividers and input borders |
--deskbell-border-strong | Chip borders |
--deskbell-accent | Brand colour |
--deskbell-accent-contrast | Text on the accent colour |
--deskbell-accent-subtle | Tinted accent background |
--deskbell-header-bg | Panel header background |
--deskbell-header-text | Panel header text |
--deskbell-bubble-user-bg | Visitor message background |
--deskbell-bubble-user-fg | Visitor message text |
--deskbell-bubble-assistant-bg | Answer background |
--deskbell-bubble-assistant-fg | Answer text |
--deskbell-bubble-radius | Message bubble radius |
--deskbell-launcher-bg | Launcher background |
--deskbell-launcher-fg | Launcher icon colour |
--deskbell-launcher-size | Launcher diameter |
--deskbell-launcher-offset-x | Launcher distance from the side |
--deskbell-launcher-offset-y | Launcher distance from the bottom |
--deskbell-radius | Panel corner radius |
--deskbell-panel-width | Panel width |
--deskbell-panel-height | Panel height |
--deskbell-shadow | Panel shadow |
--deskbell-z | Stacking order |
--deskbell-font | Font stack |
--deskbell-font-size | Base font size |
--deskbell-control-radius | Pills and buttons |
--deskbell-input-radius | Text inputs |
--deskbell-focus-ring | Focus outline colour |
--deskbell-code-bg | Fenced code block background in answers |
--deskbell-code-fg | Fenced code block text in answers |
Parts
Shape and layout, through ::part(). Rules the host page writes against a part
beat the widget's own, because normal declarations from the outer page win over
shadow-tree rules.
::part(launcher-container)::part(launcher)::part(launcher-icon)::part(launcher-label)::part(panel)::part(header)::part(header-title)::part(header-subtitle)::part(back-button)::part(close-button)::part(list)::part(empty-state)::part(suggestion)::part(message)::part(bubble)::part(citations)::part(citation-pill)::part(citation-label)::part(feedback)::part(feedback-button)::part(conversation)::part(new-question-button)::part(composer)::part(composer-input)::part(send-button)::part(powered-by)::part(md-heading)::part(md-list)::part(md-code)::part(md-link)::part(header-actions)::part(disclaimer)::part(typing)::part(welcome-title)::part(welcome)::part(welcome-card)::part(welcome-card-icon)::part(welcome-card-title)::part(welcome-card-description)::part(welcome-prompt)::part(feedback-note)::part(feedback-thanks)::part(sidebar)::part(sidebar-toggle)::part(new-thread-button)::part(scope-tabs)::part(scope-tab)::part(thread)::part(thread-title)::part(thread-meta)::part(thread-delete)::part(thread-confirm)::part(clarify-options)::part(clarify-option)::part(actions)::part(action)::part(action-title)::part(action-status)::part(action-buttons)::part(action-card)::part(action-details)
A citation pill also carries citation-kind-<type>, where the type is the
connector of the source the page came from, for example docs-crawler. Style
one kind apart from the others, or label it:
deskbell-widget::part(citation-kind-docs-crawler)::before {
content: "Docs ";
font-weight: 600;
}A cited written answer is labelled by the widget
itself: a pen glyph, the question, and a second line reading "Written answer".
The line is the writtenAnswer copy key, so rename or translate it with
copy, and it carries the citation-label part for styling. The pill's own
part is citation-kind-corrections.
Slots
Replace a region with your own markup.
<deskbell-widget project-key="pk_live_...">
<button slot="launcher">Ask the docs</button>
</deskbell-widget>slot="launcher"slot="header"slot="header-actions"slot="empty-state"slot="footer"
Following the page's theme
color-scheme-selector names the element your site keeps its theme on,
usually html. When its class, data-theme, data-color-mode or
data-bs-theme says dark or light, the widget follows it and keeps
following as the visitor toggles. Otherwise the configured color-scheme
applies.
<deskbell-widget project-key="pk_live_..." color-scheme-selector="html"></deskbell-widget>Recipes
A full-height side panel
<script
async
src="https://your-deskbell.example.com/deskbell.js"
data-project-key="pk_live_..."
data-position="bottom-left"
data-launcher="none"
data-open-on-load="true"
></script>deskbell-widget::part(panel) {
top: 0;
bottom: 0;
left: 0;
height: auto;
width: min(420px, 100vw);
border-radius: 0;
}
/* The widget is position: fixed and overlays the page. Make room for it. */
body {
padding-left: min(420px, 100vw);
}Pinning top and bottom is enough. Leave height: auto and the panel fills
the gap; height: 100vh is wrong on mobile, where browser chrome overlaps the
viewport.
Set position="bottom-left" even though the ::part() rule already sets left.
It clears the default right offset, which a right-to-left page would otherwise
honour, snapping the rail back to the opposite edge.
launcher="none" drops the bubble and open-on-load keeps the rail up. Omit
both to open it from your own control instead. The close button still renders;
hide it with deskbell-widget::part(close-button) { display: none } if the rail
should never close.
Reach of CSS
Recent conversations and the open thread are one view, not two panes. The widget shows one or the other, never both. A layout with the conversation list permanently beside the thread is out of reach from CSS, because the markup for both never exists at the same time.
Configure the widget
The four layers of widget configuration, their precedence, and every option the element accepts, listed from the descriptor the widget itself reads.
Behaviour
The widget's modes and content features, from inline mode and welcome cards to feedback reasons, the thread sidebar, conversation context, the draggable launcher and how answers render.