Chat UI
The React binding ships two chat components. Both must be mounted inside AppilotsWebProvider.
AppilotsChatFab— a launcher button plus a chat that opens as a floating card or a docked side view. It needs no layout space. This is what most sites want.AppilotsChat— the chat alone, for embedding in your own layout (a sidebar, a support page, a modal you control).
Both include Markdown replies, a multiline composer (Enter to send, Shift+Enter for a new line), stop response, new conversation, inline confirmation cards, task progress with pause/resume/cancel, and "talk to a person". Their styles are scoped and bundled, so there's no CSS to import. The chat's own UI is hidden from the agent, so it never reads its own transcript or presses its own buttons.
AppilotsChatFab
import { AppilotsChatFab } from '@appilots/web-sdk/react';
<AppilotsChatFab
locale="en"
title="Assistant"
position="bottom-right"
accentColor="#285b45"
suggestedPrompts={['What can I do here?']}
/>;
It renders in a portal under document.body, so overflow or transforms on your containers can't clip it. It starts closed, and opening moves focus to the composer. Escape, the close control, or the launcher closes it. Closing keeps the conversation, the draft, pending confirmations, and human support. It doesn't stop a reply in progress: while one runs with the chat closed, a floating "Stop response" button appears next to the launcher.
Props
Accepts every AppilotsChat prop except onClose and hidden, plus:
| Prop | Type | Default | Description |
|---|---|---|---|
position | 'bottom-right' | 'bottom-left' | 'bottom-right' | Launcher corner. With layout="panel", also the side the view docks to. |
accentColor | string | — | Launcher and focus color. |
zIndex | number | 1000 | Keep your own blocking dialogs above the widget, or lower this value to fit your stacking order. |
defaultOpen | boolean | false | Start open. Ignored when open is set. |
layout | 'popover' | 'panel' | 'popover' | Floating card, or a full-height side view. |
panelWidth | number | 400 | Side view width in CSS pixels. |
pushContent | boolean | true | With layout="panel", push the page aside instead of covering it. |
open | boolean | — | Controlled open state. Pair it with onOpenChange. |
onOpenChange | (open: boolean) => void | — | Called whenever the chat asks to open or close: Escape, the close control, or the launcher. |
launcher | boolean | true | Show the floating button. Set false when you render your own trigger. |
Side view
<AppilotsChatFab layout="panel" />
layout="panel" opens the chat as a full-height view docked beside the page instead of a floating card, so users watch the agent operate the page next to the conversation. The launcher hides while the view is open and gets focus back when it closes. Below 640px wide, the view takes the whole screen.
By default it pushes the page aside by giving <body> a margin on that side, which works for apps laid out in normal flow. If your shell uses position: fixed, or you want to animate the change, pass pushContent={false} and lay out against what the widget sets on <html> while the view is open:
html[data-appilots-panel='right'] .app-shell {
margin-right: var(--appilots-panel-width);
}
Opening from your own button
Control the chat and hide the launcher. Focus returns to whatever opened it:
const [open, setOpen] = useState(false);
<button aria-expanded={open} onClick={() => setOpen(!open)}>Assistant</button>
<AppilotsChatFab layout="panel" launcher={false} open={open} onOpenChange={setOpen} />
AppilotsChat
import { AppilotsChat } from '@appilots/web-sdk/react';
<AppilotsChat
locale="en"
title="Assistant"
placeholder="Write a message…"
suggestedPrompts={['What can I do here?']}
style={{ height: 600 }}
/>;
| Prop | Type | Default | Description |
|---|---|---|---|
locale | 'en' | 'pt-BR' | 'en' | Language of the chat's own text. The agent's replies follow the user, not this prop. |
title | string | — | Header title. |
placeholder | string | — | Composer placeholder. |
suggestedPrompts | string[] | — | Shown when the chat is empty. A suggestion fills the composer; it never sends on its own. |
style | CSSProperties | — | Styles for the chat container, for example its height. |
speech | 'browser' | SpeechHost | off | Voice dictation. See Voice input. |
onClose | () => void | — | Shows a close control and calls this when it's used. Use it when the chat lives in a panel you control. |
hidden | boolean | false | You hid the chat without unmounting it. Releases the microphone. |
Replies support headings, lists, bold, italic, inline and fenced code, and HTTP(S) links. HTML is rendered as text.
"Talk to a person" uses human escalation: waiting and connected status, operator replies, and the user's messages all stay in the same transcript. An operator must be available in the dashboard for someone to answer. Starting a new conversation abandons an open handoff.
Accessibility
The chat targets WCAG 2.2 AA:
- The floating chat is a named, non-modal dialog, and confirmation cards are inline
role="alertdialog"elements. Each card focuses Cancel first, and Escape cancels it without closing the chat. - Streamed replies are announced once when complete, not token by token. Long turns announce "Still working…" every 20 seconds.
- The action the agent is performing in the page (for example, "Clicking a button…") is announced from a status region, so screen-reader users hear why the page changed.
- Text sizes use
rem, so the chat follows the browser's text-size setting. Buttons are at least 44px. - Animations turn off under
prefers-reduced-motion: reduce.