Get started

Languages and branding

Every string a reporter sees lives in a Locale: six status messages and the widget's ui labels. bugbottle/locales ships English, Danish, Swedish, Norwegian, German, Dutch, French and Spanish, and resolveLocale(navigator.language) picks one. Override any label, or write a locale of your own — the type tells you what is required:

ts
import { da, resolveLocale } from "bugbottle/locales";

useBugReport({ endpoint, messages: da.messages });

mountBugbottle({
  endpoint,
  locale: resolveLocale(navigator.language),
  texts: { title: "Hjælp os med at gøre det bedre", trigger: "Fejl?" },
  messages: { sent: "Tak — vi kigger på det i morgen tidlig" },
});

Five more languages, imported on purpose #

A locale is data, and data is carried whole: everything that imports bugbottle/locales pays for all eight languages in it. Italian, Polish, Portuguese, Finnish and Ukrainian are in a second entry so that a site in one of them can have its own language without every other site growing. Import the whole map, or the single language the site is in:

ts
import { en, locales, resolveLocale } from "bugbottle/locales";
import { localesExtra } from "bugbottle/locales-extra";

const all = { ...locales, ...localesExtra };
mountBugbottle({ endpoint, locale: resolveLocale(navigator.language, en, all) });

resolveLocale takes the map to look in as its third argument, so nothing about this reaches a bundle that does not ask for it — not the core, and not either script-tag build, which still carry the eight. pt is European Portuguese and pt-BR resolves to it, the way da-DK resolves to da.

Branding and theme #

The panel's look comes from theme and from brand (name, logo as an image URL or inline SVG). Every value in theme is also a CSS custom property on the host element, so a stylesheet can restyle the panel without touching JavaScript:

css
[data-bugbottle="ui"] { --bb-primary: #0f766e; --bb-font: "Inter", sans-serif; }

The whole list, and nothing else:

CSS variable theme key What it is
--bb-primary primary The brand colour: the button, the send action, the marks the annotator draws
--bb-on-primary onPrimary The text and icons that sit on the brand colour
--bb-bg background The panel's ground
--bb-text text The ink
--bb-muted muted Hints, notes and the status line
--bb-border border The rules around the panel and its fields
--bb-radius radius The corner radius, as a CSS length
--bb-font font The font stack the panel is set in
--bb-shadow shadow The shadow under the panel
--bb-z zIndex Where the panel sits against the application
position Which corner it lives in: "bottom-right" (the default), "bottom-left", "top-right" or "top-left"
scheme "light", "dark" or "auto""auto" follows the reader's system setting

The last two are not custom properties: they are the data-pos and data-scheme attributes on the host, which the panel's own stylesheet reads.

None of these survive Windows High Contrast, and they are not meant to. Under forced-colors: active the browser throws every colour away and substitutes one from the reporter's own palette, so the panel stops asking for its brand colour and says the same things in system colours instead: ButtonText for the edge of the trigger and the send button, whose background was their whole shape; Highlight and HighlightText for the selected report type, the active drawing tool and the armed element picker; Highlight for the focus ring; and GrayText for a disabled action, since forced colours do not dim an opacity. The attached picture and the annotator canvas keep their own pixels — a mark's colour is the mark — and so does anything a mark was drawn in. There is nothing to configure: it happens when the reporter's system asks for it.

The theme playground on the documentation site restyles a real panel as you move these controls and prints the mountBugbottle call and the CSS block to copy. It prints only the keys you moved, so the block you copy leaves scheme alone and your panel goes on following the reader's system setting.

Edit this page on GitHub