@smooai/chat-widget
v0.15.0
Published
Embeddable AI chat as a framework-light web component — the Aurora Glass design, streaming replies, grounded sources, and per-brand theming. Speaks the smooth-operator WebSocket protocol.
Maintainers
Readme
A self-contained, streaming chat surface you drop into any site with one tag. No React on the host page, no CSS to import, ~19 kB gzipped, with the smooth-operator protocol client built in.
<smooth-agent-chat> is a self-contained chat web component for the
smooth-operator protocol. Drop in one
<script> tag (or import the ESM module) and you get a polished, streaming,
shadow-DOM-isolated chat experience — the "Aurora Glass" design — that adapts
to any host brand from a single accent color.
No React on the host page. No CSS to import. ~19 kB gzipped, protocol client included.
<script src="https://unpkg.com/@smooai/chat-widget/dist/chat-widget.global.js"></script>
<smooth-agent-chat endpoint="wss://your-host/ws" agent-id="…" agent-name="Support"></smooth-agent-chat>Live demo: open
index.html(it runs entirely in the browser against an in-page mock of the protocol — no backend needed).
Why this widget
- Aurora Glass design — a spring launcher with a live presence pulse, a glass-depth panel, gradient brand avatar + status dot, an animated typing indicator, message rise-in, refined source cards, and an icon composer.
- Brand-adaptive — pass one
primarycolor and the gradients, bubbles, glow, and depth shades derive themselves. Works light or dark. - Streaming + sources — token-by-token replies with a typing indicator and a collapsible "Sources" disclosure for knowledge-grounded answers.
- Popover or full-page — a floating launcher, or a full-bleed
/chatsurface. Same component, one attribute. - Framework-light & isolated — a standard custom element with Shadow-DOM style isolation. Use it with React, Vue, Svelte, Astro, or no framework at all.
- Secure by construction — message + citation text is rendered via
textContent, and citation links are restricted tohttp(s)(nojavascript:/data:XSS).
Install
pnpm add @smooai/chat-widget
# or: npm i @smooai/chat-widget · yarn add @smooai/chat-widget@smooai/smooth-operator (the protocol client) is a runtime dependency and is
installed automatically.
Quick start
1. Recommended — the deferred loader (best Core Web Vitals)
Include the tiny loader (~2 KB gzipped) eagerly. It does nothing expensive on
load — it waits until the page is past its critical render (requestIdleCallback
after load, or the visitor's first pointer/keydown/scroll, or an 8 s
fallback), and only then injects the full widget module. The widget never
competes with your page's LCP/TBT, but it's instantly there the moment a visitor
shows intent.
<script>
window.SmoothAgentChatConfig = {
endpoint: 'wss://your-host/ws',
agentId: '11111111-1111-4111-8111-111111111111',
agentName: 'Support',
greeting: 'Hi! How can I help?',
};
</script>
<script src="https://unpkg.com/@smooai/chat-widget/dist/chat-widget-loader.global.js" async></script>The loader resolves the widget module as a sibling of its own URL (override with
data-src), so a single CDN path is all you need. For the simplest installs you
can skip the config global and use data-* attributes on the loader tag
(data-endpoint, data-agent-id, data-primary, data-mode).
2. Declarative — eager <script> + the element
Simplest, but the module evaluates during page load — prefer the loader above on performance-sensitive (especially marketing) pages.
<script src="https://unpkg.com/@smooai/chat-widget/dist/chat-widget.global.js"></script>
<smooth-agent-chat
endpoint="wss://your-host/ws"
agent-id="11111111-1111-4111-8111-111111111111"
agent-name="Support"
greeting="Hi! How can I help?"
></smooth-agent-chat>The IIFE bundle auto-registers the element on load.
3. Programmatic — bundler / ESM
import { mountChatWidget } from '@smooai/chat-widget';
const widget = mountChatWidget({
endpoint: 'wss://your-host/ws',
agentId: '11111111-1111-4111-8111-111111111111',
agentName: 'Support',
theme: { primary: '#8b5cf6' },
});
// Drive it imperatively:
widget.openChat();
widget.closeChat();Or register the element and place it yourself:
import { defineChatWidget } from '@smooai/chat-widget';
defineChatWidget(); // now <smooth-agent-chat> works anywhere in your markupTheming
Every color is a CSS custom property under the hood, so the simplest possible
theme is a single primary — the launcher gradient, send button, user bubbles,
ambient glow, and derived depth shades all follow from it.
mountChatWidget({
endpoint, agentId,
theme: {
primary: '#ff5d6e', // the one color most brands need to set
background: '#ffffff', // light panel
text: '#1f2430',
},
});| Token | Drives | Default |
| ---------------------- | --------------------------------------------------- | ------------------ |
| primary | Launcher, send button, user bubble, glow, avatar | #00a6a6 |
| primaryText | Text/icon on top of primary | #f8fafc |
| background | Panel background | #040d30 |
| text | Foreground text + derived inset surfaces | #f8fafc |
| assistantBubble | Inbound (assistant) bubble background | #06134b |
| assistantBubbleText | Inbound bubble text | #f8fafc |
| userBubble | Outbound (user) bubble background | primary |
| userBubbleText | Outbound bubble text | primaryText |
| border | Panel + input hairline | rgba(255,255,255,.1) |
Two further tokens — a darker primary-2 (gradient depth) and a surface-2
inset wash — are derived in CSS from primary/text, so you never have to
supply them and they adapt automatically to light or dark themes.
Dashboard parity: the theme also accepts the SmooAI agent dashboard's 10-color model —
secondarypluschatBubbleInbound/chatBubbleInboundText/chatBubbleOutbound/chatBubbleOutboundText(aliases that win over the canonical keys) — so a config exported from the dashboard themes the widget directly.
Visitor identity & starter prompts
mountChatWidget({
endpoint, agentId,
examplePrompts: ['How do I get started?', 'Do you integrate with HubSpot?'],
requireName: true,
requireEmail: true, // gate the chat behind a pre-chat form…
// allowAnonymous: true, // …or let visitors skip it entirely
});examplePromptsrender as clickable chips in the empty state (max 5).showSuggestedReplies(defaulttrue) shows mid-conversation suggested-reply chips under the latest assistant message when the agent returns follow-up suggestions; tapping one sends it. Setfalseto hide them.requireName/requireEmail/requirePhoneshow a styled pre-chat form; the collected name/email are attached to the conversation session (phone rides session metadata). SetallowAnonymous: trueto skip the form.
OTP & tool confirmation (HITL)
When a turn pauses for OTP verification or a tool-write approval, the
widget shows an inline overlay above the composer — an OTP code prompt (with
masked destination + retry state) or an Approve/Decline confirmation — and
resumes the turn automatically. Under the hood the ConversationController
surfaces otp_verification_required / write_confirmation_required via an
onInterrupt callback and resumes with verifyOtp(code) / confirmTool(approved),
so you can also drive it programmatically.
Full-page mode
Render the chat as a full-bleed surface (a /chat route, a docs sidebar, an
iframe) instead of a floating launcher:
<smooth-agent-chat mode="fullpage" endpoint="wss://…/ws" agent-id="…"></smooth-agent-chat>import { mountFullPageChat } from '@smooai/chat-widget';
mountFullPageChat({ endpoint, agentId, agentName: 'Support' }, document.getElementById('chat'));Configuration
Declarative attributes mirror the programmatic ChatWidgetConfig:
| Attribute | Config key | Notes |
| --------------- | ---------------- | -------------------------------------------------- |
| endpoint | endpoint | Required. smooth-operator WebSocket URL. |
| agent-id | agentId | Required. UUID of the agent. |
| agent-name | agentName | Header label + monogram. Default Assistant. |
| logo-url | logoUrl | Brand logo in the full-page header tile (http(s) only). Falls back to the Smooth icon. |
| placeholder | placeholder | Composer placeholder. |
| greeting | greeting | Shown before the first message. |
| mode | mode | popover (default) or fullpage. |
| start-open | startOpen | Open the panel immediately (no launcher click). |
| hide-branding | hideBranding | Hide the "powered by smooth-operator" tag + footer link. Default shown. |
| show-tool-activity | showToolActivity | Show the agent's tool activity as inline chips interleaved with its prose. Default off (end-users normally shouldn't see raw tool calls). |
| — | theme | Brand colors (see Theming). |
| — | userName / userEmail | Optional participant identity. |
Programmatic API
mountChatWidget(config, target?) and mountFullPageChat(config, target?) return
the element, which exposes:
configure(partialConfig)— merge overrides (e.g. live theme tweaks) and re-render.openChat()/closeChat()— toggle the popover panel.
How it works
The widget is pure view + a thin ConversationController that speaks the
smooth-operator protocol via @smooai/smooth-operator:
connect() → WebSocket + create_conversation_session
send(text) → send_message → stream_token … (live) … → eventual_response (+ citations)The wire protocol is owned by smooth-operator; this package only renders it. That keeps one source of truth for the protocol and lets the widget stay tiny.
Browser support
Evergreen browsers (Chrome/Edge 111+, Safari 16.4+, Firefox 113+). The design uses
color-mix() to derive brand shades and ::part() for host-side customization.
Local development
pnpm install
pnpm build # tsdown → dist/ (ESM + IIFE)
pnpm typecheck # tsc --noEmit
pnpm test # vitest (jsdom) unit + render smoke tests
pnpm check # typecheck + test + build
pnpm test:e2e # Playwright live e2e (gated — see e2e/)Open index.html (e.g. pnpm dlx serve .) after a build for the interactive,
backend-free showcase.
Part of Smoo AI
@smooai/chat-widget is built and open-sourced by Smoo AI — the AI-powered business platform with AI built into every product: CRM, customer support, campaigns, field service, observability, and developer tools.
- 🚀 Customer support on the platform — smoo.ai/platform/support
- 🧰 More open source from Smoo AI — smoo.ai/open-source
- 🧩 Sibling repos — smooth-operator (the protocol it renders), smooth-operator-core (the engine), @smooai/config, @smooai/logger
Contributing
Issues and PRs welcome. Run pnpm check (typecheck + test + build) before opening
a PR.
License
MIT © Smoo AI
