> ## Documentation Index
> Fetch the complete documentation index at: https://docs.connectly.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Configure

> Override your dashboard appearance settings per page using the config object, HTML attributes and CSS custom properties 🎨

<Accordion title="Connectly Webchat is in development">
  This widget is being rolled out. Interfaces on this page may change before general
  availability. The engineering documentation site, which tracks the current build, is at
  [webchat.connectly.ai/docs](https://webchat.connectly.ai/docs/).
</Accordion>

**Most of the appearance is not configured in code.** Colours, the launcher's side and
icon, the panel's size and the greeting are stored against your client key in the
Connectly dashboard and fetched at runtime, so the common case needs no config at all —
change it in the dashboard and every page using that key follows, with no redeploy.
Everything below is for what the dashboard cannot cover: a per-page override, a value
driven by your own state, or a theme that has to match the page it sits on.

## The precedence chain

Four layers, lowest to highest:

```text theme={null}
built-in defaults  <  dashboard settings  <  `config`  <  HTML attributes
```

They merge **per group**, not wholesale, so `{ launcher: { side: 'left' } }` moves the
launcher without resetting its size, icon and offsets to defaults.

**HTML attributes get the last word.** An attribute is in the page's own markup, authored
by whoever owns the page; `config` is often set by a shared wrapper or component library
that the page author cannot edit. So `<connectly-webchat side="left">` wins over
`config={{ launcher: { side: 'right' } }}`.

One consequence worth knowing: `title` is a global HTML attribute, so anything that sets
it on the element — a CMS, a framework, a tooltip helper — overrides `config.panel.title`.
See the `title` row under "Attributes" below. If you set the panel heading through
`config`, make sure nothing is also writing a `title` attribute.

`init()` is the one place the shorthands and `config` are reconciled for you: the
`title`/`width`/`height` options land as attributes, so when a single `init()` call passes
both a shorthand and a `config` for the same field, the shorthand yields to `config` and
logs a warning rather than beating it from the top tier.

```tsx theme={null}
<ConnectlyWebchat
  clientKey="<your-client-key>"
  config={{
    theme: { accent: '#6c2bd9', colorScheme: 'auto' },
    launcher: { side: 'left', label: 'Chat with us' },
    panel: { width: 380, height: 560 },
  }}
/>
```

Outside React, assigning `config` alone repaints nothing — it is a plain field, not an
attribute, so call `reload()` after:

```js theme={null}
const el = document.querySelector('connectly-webchat');
el.config = { theme: { accent: '#c026d3' } };
el.reload();
```

> **Each distinct `config` value costs a network round-trip.** Values are compared
> structurally, so an equal object is free — but bind `config` to a colour picker and you
> send one request per intermediate value. Memoise it, apply on commit, or for a live
> preview drive the `--cwc-*` custom properties instead (see "Theming with CSS" below).

## `config` fields

`config` is a partial `WidgetUi` — the same shape the dashboard saves.

* **`launcher`** — `side`, `offsetX`, `offsetY`, `size`, `shape` (`circle` | `pill`),
  `label`, `ariaLabel`, `icon` (`{ kind: 'default' | 'url' | 'none', url }`)
* **`panel`** — `width`, `height`, `radius`
* **`theme`** — `accent`, `accentText`, `surface`, `surfaceAlt`, `text`, `textMuted`,
  `border`, `bubbleVisitor`, `bubbleVisitorText`, `bubbleAgent`, `bubbleAgentText`,
  `bubbleRadius`, `fontFamily`, `colorScheme` (`light` | `dark` | `auto`)
* **`zIndex`**
* **`collision`** — `bottomOffsetPx`, `maxBottomOffsetPx`
* **`mobile`** — `breakpointPx`, `launcher` (`offsetX`, `offsetY`, `size`), `panel`
  (`fullscreen`, `width`, `height`, `radius` — `0` means "inherit the desktop value")

Visible in autocomplete but **not yet acted on**, so setting them does nothing:
`behavior.autoOpen*`, `navigation.linkTarget`, `paths.*`, `panel.anchor`,
`launcher.hideOnMobile`, `collision.bottomOffsetSelectors`,
`collision.hideBehindModalDialog`, `position`, `bundleVersion`.

**Only the config stored for your business is range-checked.** Values passed through
`config` or an attribute are merged in as given, so `panel.width: 5000` is a 5000px panel.
Use the dashboard's ranges as your bounds. Note this cuts both ways with the precedence
order above: an out-of-range attribute is not clamped *and* cannot be corrected by
`config`.

And `fontFamily` **names** a face, it cannot load one: `@font-face` is ignored inside a
shadow root, so declare the face in your own stylesheet and name it here.

## Attributes

Every attribute is optional except `client-key`.

| attribute                     | meaning                                                                                                                                                                                                                                                                                                                |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `client-key`                  | Required.                                                                                                                                                                                                                                                                                                              |
| `title`                       | The panel heading — **not** a tooltip, despite the attribute name. Load-bearing config: as the top precedence tier it overrides `config.panel.title`, so do not set it for tooltip purposes.                                                                                                                           |
| `width`, `height`             | Panel size in bare pixels: `width="380"`. `"380px"` parses to `NaN` and is ignored. **Not range-checked** — see "Only the config stored for your business is range-checked" above. On desktop `height` is capped at the viewport in CSS (`min(…, 100dvh)`); `width` is not, and the mobile panel height is not either. |
| `side`                        | `left` or `right`.                                                                                                                                                                                                                                                                                                     |
| `offset-x`, `offset-y`        | Launcher offset from its corner, in pixels.                                                                                                                                                                                                                                                                            |
| `z-index`, `bottom-offset-px` | Stacking, and a flat lift above a cookie bar or a sticky cart.                                                                                                                                                                                                                                                         |
| `open`                        | Panel open. Value-aware: `open` and `open=""` are open, `open="false"` and an absent attribute are closed. In JSX just write `open={isOpen}`.                                                                                                                                                                          |
| `log-level`                   | `silent` \| `error` \| `warn` \| `info` \| `debug`. Applies immediately, including after mount.                                                                                                                                                                                                                        |

## React props

| prop           | reactive | notes                                                                                                                                                                                                                              |
| -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `clientKey`    | no       | Changing it remounts the widget: a different key is a different business, so session, room and transcript all reset.                                                                                                               |
| `config`       | yes      | Presentation overrides. An inline object literal is fine — see the round-trip warning above.                                                                                                                                       |
| `open`         | yes      | Omit it and the widget owns its own state; pass it and you own it, and a value you never update pins the panel there. Mounting with `open={true}` comes up showing the panel, with no closed-then-open flash.                      |
| `onOpenChange` | —        | `(open: boolean) => void`, fired for every open and close whoever caused it. On its own, without `open`, it is the read-only version: the widget stays in charge and you just observe. An inline arrow never re-mounts the widget. |

`log-level` is not a React prop: set it with `setAttribute`, or write it directly in JSX.

## Theming with CSS

The `--cwc-*` custom properties are the supported theming API. Every resolved value is
written to a custom property on the host element, with no `!important` anywhere in that
path, so yours wins:

```css theme={null}
connectly-webchat {
  --cwc-accent: #6c2bd9;
  --cwc-launcher-size: 56px;
  --cwc-panel-radius: 20px;
}
```

`--cwc-*` is desktop and `--cwc-m-*` is mobile, switched by a media query. Lengths take
units here (`56px`), unlike `config`, which takes plain numbers. This is also the layer
for anything that changes rapidly — it costs no network round-trip at all.

**Reaching inside the shadow root is not supported.** Class names and structure change
without notice; a stylesheet that depends on them will break on an ordinary widget update.
