Skip to main content

Theme

Styling the widget has two layers:

  1. themePreset — pick a built-in base palette: "dark" (default) or "light". Both use the Kraken pink accent.
  2. theme — override individual values (colours, fonts, sizing, trigger placement) on top of the selected preset. You can also set the equivalent CSS variables directly on the host element.

Stacking is controlled by zIndex (the base layer for the floating trigger). The panel always sits one step above (zIndex + 1).

Dark & light presets​

The widget ships with two complete palettes. themePreset selects which one is used as the base.

Widget with the light theme preset
themePreset: 'light'
Widget with the dark theme preset
themePreset: 'dark' (default)
setConfig({
apiUrl,
accountNumber,
userHandle,
themePreset: 'light', // "dark" (default) | "light"
});
  • themePreset is a top-level config key — a sibling of theme, not a key inside it.
  • If omitted or set to an unknown value, the widget uses "dark".
  • The preset only sets the base palette. Any keys you set in theme still win (see Overriding specific values).
note

The widget does not automatically follow the operating system's colour scheme — it renders the preset you choose. To mirror the OS (or your app's) theme, switch the preset yourself; see Following the OS colour scheme.

Overriding specific values​

Set only the keys you want to change; everything else comes from the selected preset. This works with or without themePreset.

setConfig({
apiUrl,
accountNumber,
userHandle,
themePreset: 'light',
theme: {
accentColor: '#2563eb', // override just the brand accent
borderRadius: '0.5rem',
fontSize: '14px',
},
});

Order of precedence (highest wins):

theme overrides → selected themePreset → default preset ("dark")

Unknown theme keys are ignored with a console warning that lists the known ones, so a typo or an old key name shows up in the console.

Check accessibility when customising

Because the theme gives you full control over colours, fonts, and sizing, it's your responsibility to keep the result accessible — the widget can't enforce this for you. When overriding values, verify:

  • Contrast between text and its background meets WCAG AA (at least 4.5:1 for body text, 3:1 for large text). This applies to accentTextColor on accentColor, the bot bubbles (botBubble*), body text, and muted text. The default pink with white text sits right at 4.5:1, so even a slightly lighter accentColor needs a darker accentTextColor.
  • Readability — avoid overly small fontSize values or hard-to-read fontFamily choices.
  • Changes still hold up in both light and dark contexts if your site switches presets.

A quick way to check is your browser's DevTools accessibility/contrast inspector, or a checker like the WebAIM Contrast Checker.

Overriding via CSS variables​

Instead of (or in addition to) the theme object, you can set CSS variables on the ink-live-chat-widget host element:

ink-live-chat-widget {
--ilcw-background-color: #16161e;
--ilcw-accent-color: #df1d80;
--ilcw-font-size: 16px;
--ilcw-trigger-size: 4.5em;
--ilcw-trigger-panel-gap: 1em;
}

Or imperatively on the element instance:

document
.querySelector('ink-live-chat-widget')
.style.setProperty('--ilcw-accent-color', '#2563eb');

Each variable is --ilcw- plus the kebab-case theme key — for example, accentColor becomes --ilcw-accent-color. See the CSS variable reference below.

Following the OS colour scheme​

To make the widget track the visitor's OS preference (or your app's own light/dark toggle), pick the preset with matchMedia and update it when it changes:

const query = window.matchMedia('(prefers-color-scheme: dark)');

const el = init(document.getElementById('chat-root'), {
apiUrl,
accountNumber,
userHandle,
themePreset: query.matches ? 'dark' : 'light',
});

query.addEventListener('change', (e) => {
el.setConfig({ themePreset: e.matches ? 'dark' : 'light' });
});

Any per-key theme overrides you set continue to apply on top of whichever preset is active.

Changing themePreset or theme updates the widget's colours straight away without redrawing the chat. An open chat keeps its scroll position, the message the visitor is typing, and keyboard focus, so it's safe to switch presets or brand colours while they're chatting.

Default values by preset​

Colour values differ between presets; the sizing/typography values are shared.

Colours​

KeyDark (default)LightHost CSS variableDescription
accentColor#df1d80#df1d80--ilcw-accent-colorBrand accent. Background of the floating trigger, the visitor's own message bubbles, the send button, the primary buttons (end chat, retry, start a new conversation), and the message field's focus border.
accentTextColor#ffffff#ffffff--ilcw-accent-text-colorText and icons drawn on accentColor.
backgroundColor#16161e#fafafa--ilcw-background-colorSurface background: the chat panel, the message field, the emoji picker, and dialogs.
borderColor#2a2a38#e5e5e5--ilcw-border-colorBorders and dividers — panel edge, header/input separators, date separators.
botBubbleBgColor#2a2a38#e5e5e5--ilcw-bot-bubble-bg-colorBackground of inbound message bubbles (from the support side — bot or human agent).
botBubbleTextColor#f0f0f8#262626--ilcw-bot-bubble-text-colorText colour inside inbound (support) bubbles.
mutedTextColor#8080a0#737373--ilcw-muted-text-colorSecondary text and icons — timestamps, date separators, the input placeholder, the empty-state description, header buttons, and focus outlines. Lower emphasis than textColor.
shadow0 4px 12px rgba(0, 0, 0, 0.15)0 4px 12px rgba(0, 0, 0, 0.15)--ilcw-shadowDrop shadow for the panel, the trigger, and floating controls.
textColor#f0f0f8#171717--ilcw-text-colorPrimary text — header title, empty-state title, and general body copy.

Sizing & typography (shared by both presets)​

KeyDefaultHost CSS variableDescription
borderRadius1em--ilcw-border-radiusCorner radius for the panel, message bubbles, and controls.
fontFamilysystem-ui, -apple-system, sans-serif--ilcw-font-familyBase font family for all widget text.
fontSize16px--ilcw-font-sizeBase font size. All other text scales relative to this using em, so this effectively controls the overall widget scale.
triggerEdgeInset1.5em--ilcw-trigger-edge-insetDistance from the viewport edge(s) to the floating trigger.
triggerPanelGap1em--ilcw-trigger-panel-gapGap between the floating trigger and the chat panel when it is open.
triggerPositionbottom-right(sets data-ilcw-trigger-position on the element)Which viewport corner the trigger sits in: bottom-right, bottom-left, top-right, or top-left.
triggerSize4.5em--ilcw-trigger-sizeDiameter of the floating trigger button.
zIndex99999--ilcw-z-indexCSS z-index of the floating trigger. The panel sits one step above (this value + 1). Raise it if the widget is hidden behind other fixed elements.
note

triggerPosition is not a colour/size variable — it sets a data-ilcw-trigger-position attribute on the element (bottom-right, bottom-left, top-right, or top-left) used for layout positioning.

CSS variable reference​

All host CSS variables, for quick copy/paste:

ink-live-chat-widget {
--ilcw-accent-color: ;
--ilcw-accent-text-color: ;
--ilcw-background-color: ;
--ilcw-border-color: ;
--ilcw-border-radius: ;
--ilcw-bot-bubble-bg-color: ;
--ilcw-bot-bubble-text-color: ;
--ilcw-font-family: ;
--ilcw-font-size: ;
--ilcw-muted-text-color: ;
--ilcw-shadow: ;
--ilcw-text-color: ;
--ilcw-trigger-edge-inset: ;
--ilcw-trigger-panel-gap: ;
--ilcw-trigger-size: ;
--ilcw-z-index: ;
}