# Chat widget chrome (/themes/chat-widget)

The storefront's Inbox chat widget is **theme chrome**, like the promo bar. The
platform keeps the session, the live connection, message delivery and attachments
behind [`@poltura/theme-sdk/inbox`](/themes/sdk/reference/inbox). The theme decides
how the pieces are arranged.

## Where it is [#where-it-is]

Put the widget in `src/layout/chat.tsx` as the file's default export. The
storefront mounts it from that path. Without the file, the platform's complete
widget mounts instead, the same one `<InboxWidget />` draws. The default theme
ships this file:

```tsx title="src/layout/chat.tsx"
import {
  InboxChatGlyph,
  InboxComposer,
  InboxConversation,
  InboxLauncher,
  InboxOfflineForm,
  InboxPanel,
  InboxPanelHeader,
  InboxRoot,
  InboxStatusLine,
} from '@poltura/theme-sdk/inbox';

export default function ThemeChatWidget() {
  return (
    <InboxRoot className='pol-chat'>
      <InboxPanel className='pol-chat__panel'>
        <InboxPanelHeader className='pol-chat__header' />
        <InboxConversation className='pol-chat__conversation' />
        <InboxStatusLine className='pol-chat__status' />
        <InboxOfflineForm className='pol-chat__offline' />
        <InboxComposer className='pol-chat__composer' />
      </InboxPanel>
      <InboxLauncher className='pol-chat__launcher'>
        <InboxChatGlyph />
      </InboxLauncher>
    </InboxRoot>
  );
}
```

Every part must render inside `<InboxRoot>`, which renders nothing when the
store offers no chat. `useInbox()` reads the view and actions from that context.

Render `InboxConversation` as the panel body. It shows the message list, and
shows the open help article in its place once a shopper picks one. A layout that renders
`InboxMessageList` directly must switch to `InboxKnowledgeArticle` itself while
`view.knowledge.article` is set, or picking an article does nothing visible.

## Parts [#parts]

| Component                   | Props                               | Role                                                             |
| --------------------------- | ----------------------------------- | ---------------------------------------------------------------- |
| `InboxRoot`                 | `children`, `className?`            | Fixed wrapper, CSS variables, state and context                  |
| `InboxWidget`               | none                                | The complete widget, built from the parts below                  |
| `InboxLauncher`             | `className?`, `children?`           | Button; `children` replace the default glyph                     |
| `InboxPanel`                | `className?`, `children`            | Dialog (`id="poltura-inbox-panel"`)                              |
| `InboxPanelHeader`          | `className?`, `title?`, `children?` | Accent header: title, reply-time / offline status, close icon    |
| `InboxConversation`         | `className?`, `renderMessage?`      | Panel body: `InboxMessageList`, or the open article in its place |
| `InboxMessageList`          | `className?`, `renderMessage?`      | Scroll log, empty-state greeting and help, typing, jump to latest |
| `InboxMessageBubble`        | `message`, `className?`             | Default bubble                                                   |
| `InboxComposer`             | `className?`, `placeholder?`        | Pill with attach, text field and send icon                       |
| `InboxOfflineForm`          | `className?`                        | Email and message fields when `view.online === false`            |
| `InboxStatusLine`           | `className?`                        | Reconnecting / preview bar above the composer                    |
| `InboxChatGlyph`            | `size?`, `className?`               | Default launcher icon                                            |
| `InboxKnowledgeSearch`      | `className?`, `placeholder?`        | Debounced help-article search (store knowledge base)             |
| `InboxKnowledgeArticle`     | `className?`                        | Open article body with back                                      |
| `InboxKnowledgeSuggestions` | `className?`, `limit?`              | Top articles above the greeting when the thread is empty         |

`useInbox()` returns `{ view, actions }`:

- `view.copy` holds the widget's wording, already resolved: the theme's `chat`
  texts first, then the platform's `inbox.*` messages.
- `actions.send`, `attach`, `removeAttachment` and `retry` are the only chat
  actions a theme calls. `actions.open`, `close` and `toggle` drive the panel.
- `view.appearance` carries the merchant's side, colour mode and colours.
- The store's help articles live on `view.knowledge` (`enabled`, `query`,
  `results`, `loading`, `article`), with `actions.searchKnowledge`, `openArticle`
  and `closeArticle`. `enabled` is true when the store has at least one published
  article. An article links to `/guides/{category}/{slug}` when that page exists.
  Otherwise the panel shows its sanitized body inline.

The platform widget (`InboxWidget`) shows an empty thread as a greeting card and
one Help section: a search field, then up to three suggested articles.
`InboxMessageList` draws that empty state when help articles are on.
`InboxConversation` replaces the list with `InboxKnowledgeArticle` while an
article is open. "Still need help? Send a message" closes the article and
focuses the composer. In the Customizer, the help search returns sample results.
The launcher stays visible on desktop while the panel is open, and hides on
screens narrower than 640px.

## Stable classes [#stable-classes]

Restyle from `src/styles/theme.css` with `:where()`, same as the other chrome
hooks. See [Chrome stable classes](/themes/chrome-classes).

| Class                           | Node                                                                                        |
| ------------------------------- | ------------------------------------------------------------------------------------------- |
| `inbox-root`                    | fixed wrapper (`data-poltura-inbox`, `data-open`, `data-online`, `data-connection`)         |
| `inbox-launcher`                | launcher button (`aria-expanded`, `data-unread`)                                            |
| `inbox-launcher__badge`         | unread count pill on the launcher                                                           |
| `inbox-panel`                   | dialog                                                                                      |
| `inbox-panel__header`           | header row                                                                                  |
| `inbox-panel__title`            | header title                                                                                |
| `inbox-panel__status`           | one-line reply-time / offline status                                                        |
| `inbox-panel__status-dot`       | online (green) / offline (grey) dot                                                         |
| `inbox-panel__close`            | header close icon button                                                                    |
| `inbox-messages`                | `role="log"`                                                                                |
| `inbox-greeting`                | empty-thread greeting card                                                                  |
| `inbox-help`                    | empty-thread Help section (search and suggestions)                                          |
| `inbox-help__label`             | the single "Help" section label                                                             |
| `inbox-message-row`             | message wrapper containing author, bubble and metadata; `--system` for centred system text  |
| `inbox-message`                 | actual bubble only; plus `--customer`, `--staff`, `--ai`                                    |
| `inbox-message__author`         | staff / AI name row                                                                         |
| `inbox-message__disclosure`     | AI disclosure line                                                                          |
| `inbox-message__meta`           | relative time and delivery ticks                                                            |
| `inbox-message__time`           | relative timestamp                                                                          |
| `inbox-message__ticks`          | delivery copy on the last customer message                                                  |
| `inbox-day`                     | optional day separator in the log                                                           |
| `inbox-typing`                  | three-dot typing indicator                                                                  |
| `inbox-jump`                    | jump-to-latest control                                                                      |
| `inbox-composer`                | composer form                                                                               |
| `inbox-composer__input`         | auto-growing textarea                                                                       |
| `inbox-composer__attach`        | paperclip button                                                                            |
| `inbox-composer__send`          | paper-plane submit                                                                          |
| `inbox-composer__chip`          | pending attachment chip                                                                     |
| `inbox-status`                  | reconnecting / preview bar                                                                  |
| `inbox-offline`                 | offline capture form                                                                        |
| `inbox-offline--success`        | offline form success copy                                                                   |
| `inbox-knowledge-search`        | help search field and results                                                               |
| `inbox-knowledge-suggestions`   | empty-thread article rows                                                                   |
| `inbox-knowledge-article`       | open article panel                                                                          |
| `inbox-knowledge-article__body` | sanitized article HTML                                                                      |
| `inbox-knowledge-article__back` | article back control                                                                        |
| `inbox-knowledge-article__cta`  | "Still need help" control                                                                   |

Colours are CSS variables on the root: `--inbox-accent`, `--inbox-accent-text`,
`--inbox-bg` and `--inbox-text`.

## Settings [#settings]

The theme settings group `chat` (and `chat_dark` for the dark mode colours)
styles the widget in the Customizer. It does not turn chat on for the store:
that is the store's Inbox setting.

| Setting                                                          | What it does                                                             |
| ---------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `chat.enabled`                                                   | hides the launcher when false (selecting the chat in the Customizer still opens it) |
| `chat.position`                                                  | `right` or `left`                                                        |
| `chat.appearance_mode`                                           | `auto`, `light`, `dark`                                                  |
| `chat.accent` / `accent_text` / `background` / `text`            | panel colours                                                            |
| `chat.launcher_label` / `title` / `greeting` / `offline_message` | copy overrides                                                           |

Selecting the chat in the Customizer opens the panel on sample data. `InboxRoot`
does this, so theme code needs nothing for it.

## Next [#next]

- [Chrome stable classes](/themes/chrome-classes): the override pattern for every
  platform part.
- [inbox reference](/themes/sdk/reference/inbox): every export of
  `@poltura/theme-sdk/inbox`.
