@rapidaai/react-widget
v1.2.1
Published
Rapida AI chat widget — embeddable voice + text AI agent
Readme
@rapidaai/react-widget
Embeddable voice + text AI agent widget. Drop a single script tag into any website to add an intelligent chat assistant powered by Rapida.
Quick Start
Add the widget to any HTML page with two lines:
<script>
window.chatbotConfig = {
assistant_id: "YOUR_ASSISTANT_ID",
token: "YOUR_API_KEY",
};
</script>
<script src="https://cdn-01.rapida.ai/public/scripts/app.min.js"></script>That's it. A floating chat button appears in the bottom-right corner of your page.
Installation
CDN (recommended)
Use the latest version:
<script src="https://cdn-01.rapida.ai/public/scripts/app.min.js"></script>Pin to a specific version:
<script src="https://cdn-01.rapida.ai/public/scripts/v1.2.0/app.min.js"></script>npm
npm install @rapidaai/react-widgetThen import the built file from dist/app.min.js in your bundler or serve it statically.
Configuration
Set window.chatbotConfig before loading the script:
<script>
window.chatbotConfig = {
// Required
assistant_id: "your-assistant-id",
token: "your-api-key",
// Optional - API endpoint (defaults to Rapida cloud)
api_base: "https://assistant-01.in.rapida.ai",
// Optional - user identity
user: {
name: "Jane Doe",
user_id: "user-123",
meta: { plan: "pro" },
},
// Optional - identity
name: "Support Bot",
logo_url: "https://example.com/avatar.png",
// Optional - layout section
layout: {
mode: "floating", // "floating" | "docked-right" | "docked-left" | "inline"
position: "bottom-right", // "bottom-right" | "bottom-left" | "top-right" | "top-left"
corners: "square",
showFrame: true,
},
// Optional - theme section
theme: {
mode: "light", // "light" | "dark" | "system"
injectTheme: "g10", // "white" | "g10" | "g90" | "g100"
},
// Optional - AI Chat sections
aiEnabled: false,
header: {
title: "Support Bot",
showAiLabel: false,
minimizeButtonIconType: "side-panel-right",
},
launcher: {
isOn: true,
},
history: {
isOn: false,
},
messaging: {
messageTimeoutSecs: 150,
messageLoadingIndicatorTimeoutSecs: 1,
},
// Optional - misc
language: "en",
assistant_version: "latest",
debug: false,
};
</script>Configuration Model
The widget has two configuration layers:
- Rapida layer: connection, authentication, user identity, message bridge, and audio controls.
- UI layer: native IBM AI Chat configuration exposed directly on
window.chatbotConfig.
Rapida always owns messaging.customSendMessage because text messages must go through @rapidaai/react. Rapida also appends its audio controls through renderWriteableElements.afterInputElement; if you provide your own afterInputElement, it is preserved and Rapida audio is appended after it.
Use the sectioned config shape below. Do not use a carbon config key.
Required Rapida Options
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| assistant_id | string | required | Rapida assistant/deployment ID. |
| token | string | required | Public web plugin token used to authenticate the widget. |
Rapida Options
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| api_base | string | https://assistant-01.in.rapida.ai | Rapida API base URL. Use this for local or environment-specific backends. |
| assistant_version | string | latest | Assistant version to load when the backend supports versioned deployments. |
| user.name | string | Guest | Display name for the current user. |
| user.user_id | string | generated and stored locally | Stable user ID. Provide one if your host app already has an authenticated user ID. |
| user.meta | Record<string, string> | { source: "web plugin" } | Extra metadata sent to Rapida with the user session. |
| language | string | host page language or en | Locale/language passed to the UI. The widget also watches <html lang>. |
| debug | boolean | false | Enables additional client logging. Also passed to the UI layer. |
| name | string | deployment name | Friendly assistant name. Used as the default assistantName and header.title. |
| logo_url | string | default assistant avatar | Assistant avatar URL. Used as the default assistantAvatarUrl. |
Theme Options
Use theme for all theme-level options.
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| theme.mode | "light" \| "dark" \| "system" | "light" | Widget color mode. dark defaults the UI token injection to g100; light defaults it to g10; system lets the host/system decide unless theme.injectTheme is set. |
| theme.injectTheme | "white" \| "g10" \| "g90" \| "g100" | derived from theme.mode | UI theme token injected into the chat shadow DOM. Set this when the host page does not already provide compatible theme tokens. |
Layout Options
layout is a single section containing widget placement and native Carbon layout options.
window.chatbotConfig = {
layout: {
mode: "floating",
position: "bottom-right",
corners: "square",
showFrame: true,
customProperties: {
width: "420px",
height: "640px",
},
},
};| Property | Type | Default | Description |
|----------|------|---------|-------------|
| layout | object | { mode: "floating" } | Widget placement and native Carbon layout options. |
| layout.mode | "floating" \| "docked-right" \| "docked-left" \| "inline" | "floating" | Rapida placement mode. |
| layout.position | "bottom-right" \| "bottom-left" \| "top-right" \| "top-left" | "bottom-right" | Floating launcher and panel position. |
| layout.showFrame | boolean | true | Keeps the native border and shadow frame. |
| layout.hasContentMaxWidth | boolean | UI default | Constrains message content to the UI max-width. |
| layout.corners | "round" \| "square" \| object | "square" | Corner style. Use a string for all corners or an object for per-corner control. |
| layout.customProperties | Record<string, string> | generated for floating | CSS variable overrides for the chat UI. Values are raw CSS strings. |
Per-corner layout.corners object:
| Property | Type | Description |
|----------|------|-------------|
| startStart | "round" \| "square" | Top-left in LTR, top-right in RTL. |
| startEnd | "round" \| "square" | Top-right in LTR, top-left in RTL. |
| endStart | "round" \| "square" | Bottom-left in LTR, bottom-right in RTL. |
| endEnd | "round" \| "square" | Bottom-right in LTR, bottom-left in RTL. |
Supported layout.customProperties keys:
| Key | Description |
|-----|-------------|
| height | Floating chat height. |
| max-height | Floating chat maximum height. |
| width | Floating chat width. |
| min-height | Floating chat minimum height. |
| max-width | Floating chat maximum width. |
| z-index | Floating chat z-index. |
| bottom-position | Floating panel distance from viewport bottom. |
| right-position | Floating panel distance from viewport right. |
| top-position | Floating panel distance from viewport top. |
| left-position | Floating panel distance from viewport left. |
| launcher-default-size | Launcher button size. |
| launcher-position-bottom | Launcher distance from viewport bottom. |
| launcher-position-right | Launcher distance from viewport right. |
| launcher-extended-width | Expanded launcher width. |
| messages-max-width | Maximum width for message content. |
| messages-min-width | Minimum width for message content. |
| workspace-min-width | Minimum width for workspace panels. |
| card-max-width | Maximum width for card responses. |
| launcher-color-background | Launcher background color. |
| launcher-color-avatar | Launcher icon/avatar color. |
| launcher-color-background-hover | Launcher hover background. |
| launcher-color-background-active | Launcher active background. |
| launcher-color-focus-border | Launcher focus border color. |
| launcher-mobile-color-text | Mobile launcher text color. |
| launcher-expanded-message-color-text | Expanded launcher text color. |
| launcher-expanded-message-color-background | Expanded launcher background. |
| launcher-expanded-message-color-background-hover | Expanded launcher hover background. |
| launcher-expanded-message-color-background-active | Expanded launcher active background. |
| launcher-expanded-message-color-focus-border | Expanded launcher focus border color. |
| unread-indicator-color-background | Unread indicator background color. |
| unread-indicator-color-text | Unread indicator text color. |
Header Options
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| header.isOn | boolean | true | Enables the native chat header. Set false for a fully embedded/fullscreen experience with your own app header. |
| header.title | string | name or deployment name | Header title. Set "" to remove the visible title. |
| header.name | string | UI default | Secondary name shown after the title. Set "" to remove it. |
| header.minimizeButtonIconType | "close" \| "minimize" \| "side-panel-left" \| "side-panel-right" \| "side-panel-down" | side-panel icon based on dock side | Icon for the close/minimize button. |
| header.hideMinimizeButton | boolean | false | Hides the close/minimize button. |
| header.showRestartButton | boolean | false | Shows the restart conversation button. |
| header.menuOptions | Array<{ text: string }> | none | Custom menu options in the header menu. |
| header.showAiLabel | boolean | false | Shows the AI label in the header. Disabled by default. |
| header.hideDefaultAiLabelContent | boolean | true | Hides the default AI label popover content. |
| header.hasContentMaxWidth | boolean | false | Constrains the header to the message content width. |
| header.actions | ToolbarAction[] | none | Custom header toolbar actions. |
Launcher Options
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| launcher.isOn | boolean | true for floating, false for docked/inline | Shows the floating launcher button. |
| launcher.showUnreadIndicator | boolean | UI default | Shows the unread dot on the launcher. |
| launcher.mobile.avatarUrlOverride | string | none | Custom mobile launcher avatar/icon URL. |
| launcher.mobile.isOn | boolean | false | Deprecated expanded call-to-action launcher state. |
| launcher.mobile.title | string | translated default | Deprecated expanded launcher title. |
| launcher.mobile.timeToExpand | number | 15 | Deprecated delay before launcher expansion, in seconds. |
| launcher.desktop.avatarUrlOverride | string | none | Custom desktop launcher avatar/icon URL. |
| launcher.desktop.isOn | boolean | false | Deprecated expanded call-to-action launcher state. |
| launcher.desktop.title | string | translated default | Deprecated expanded launcher title. |
| launcher.desktop.timeToExpand | number | 15 | Deprecated delay before launcher expansion, in seconds. |
History Options
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| history.isOn | boolean | false | Enables the native history panel. |
| history.showMobileMenu | boolean | true | Shows mobile header menu options for new chat and view chats. |
| history.startClosed | boolean | false | Starts history closed and preserves open/closed state across responsive mode changes. |
Messaging Options
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| messaging.skipWelcome | boolean | UI default | Starts new conversations without requesting a welcome message. |
| messaging.messageTimeoutSecs | number | 150 | Message timeout in seconds. Use 0 to disable automatic timeout. |
| messaging.messageLoadingIndicatorTimeoutSecs | number | 1 | Delay before the UI shows a loading indicator. Use 0 to prevent the UI from showing one automatically. |
| messaging.customSendMessage | function | Rapida bridge | Reserved. Rapida overwrites this so text is sent through @rapidaai/react. |
| messaging.customLoadHistory | function | none | Optional function that returns native history items for the UI. |
| messaging.showStopButtonImmediately | boolean | false | Shows the stop button as soon as a message request starts. |
Input Options
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| input.maxInputCharacters | number | 10000 | Maximum characters allowed in the text input. |
| input.isVisible | boolean | true | Shows or hides the main input surface. |
| input.isDisabled | boolean | false | Disables text input. Rapida also disables text input while audio mode is active. |
Home Screen Options
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| homescreen.isOn | boolean | false | Enables the native home screen before chat. |
| homescreen.greeting | string | none | Greeting text on the home screen. |
| homescreen.starters.isOn | boolean | UI default | Shows starter buttons. |
| homescreen.starters.buttons | Array<{ label: string; isSelected?: boolean }> | none | Starter utterances displayed as buttons. |
| homescreen.customContentOnly | boolean | false | Hides the built-in greeting and starters so custom content can own the home screen. |
| homescreen.disableReturn | boolean | false | Prevents returning to the home screen after a user has sent a message. |
Upload Options
File upload is experimental in the underlying UI.
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| upload.is_on | boolean | false | Enables the attachment button. Requires upload.onFileUpload. |
| upload.accept | string | all file types | Accepted MIME types or extensions, same format as the HTML accept attribute. |
| upload.maxFileSizeBytes | number | none | Client-side maximum file size. |
| upload.maxFiles | number | none | Maximum number of pending files. |
| upload.onFileUpload | function | none | Called once per selected file. Return structured data for the pending message. |
Keyboard Shortcut Options
Keyboard shortcut configuration is experimental in the underlying UI.
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| keyboardShortcuts.messageFocusToggle.is_on | boolean | true | Enables the message/input focus toggle shortcut. |
| keyboardShortcuts.messageFocusToggle.key | string | "F6" | Primary shortcut key. |
| keyboardShortcuts.messageFocusToggle.modifiers.alt | boolean | false | Requires Alt. |
| keyboardShortcuts.messageFocusToggle.modifiers.shift | boolean | false | Requires Shift. |
| keyboardShortcuts.messageFocusToggle.modifiers.ctrl | boolean | false | Requires Control. |
| keyboardShortcuts.messageFocusToggle.modifiers.meta | boolean | false | Requires Command/Meta. |
Disclaimer Options
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| disclaimer.isOn | boolean | false | Shows a disclaimer screen before chat. |
| disclaimer.disclaimerHTML | string | required when enabled | HTML content for the disclaimer. If this changes after acceptance, the user must accept again. |
Service Desk Options
These are advanced native UI options for human-agent handoff integrations.
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| serviceDeskFactory | function | none | Factory that creates a service desk integration instance. |
| serviceDesk.availabilityTimeoutSeconds | number | UI default | Timeout used while checking whether human agents are available. |
| serviceDesk.skipConnectHumanAgentCard | boolean | false | Auto-connects to an available agent after a connect-to-agent response while still showing the card. |
| serviceDesk.agentJoinTimeoutSeconds | number | none | Timeout while waiting for an agent to join after one is requested. |
| serviceDesk.allowReconnect | boolean | true | Attempts to reconnect the user to a prior human-agent conversation when supported. |
Advanced UI Options
These are passed through to the native UI layer. Use them only when the host page needs lower-level control.
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| aiEnabled | boolean | false | Enables AI visual styling. The widget disables this by default. |
| assistantName | string | name or deployment name | Assistant name used by the UI for accessibility, errors, and defaults. |
| assistantAvatarUrl | string | logo_url | Assistant avatar URL used by native messages. |
| locale | string | language | UI locale. Prefer language unless you need to override only the UI. |
| namespace | string | "rapida-chat" | Namespace for DOM IDs, storage keys, and multi-instance isolation. Must be 30 characters or fewer. |
| openChatByDefault | boolean | true for docked/inline, false for floating | Opens the chat when it first renders. |
| shouldSanitizeHTML | boolean | true | Sanitizes assistant HTML before rendering. |
| shouldTakeFocusIfOpensAutomatically | boolean | false | Moves focus into the chat when it opens on page load. |
| disableCustomElementMobileEnhancements | boolean | false | Disables mobile enhancements that can conflict with custom element embedding. |
| isReadonly | boolean | false | Puts the chat in read-only mode for viewing old conversations. |
| persistFeedback | boolean | false | Keeps feedback controls visible beyond the latest message. |
| strings | partial language pack | UI defaults | Overrides built-in UI strings. |
| injectCarbonTheme | "white" \| "g10" \| "g90" \| "g100" | derived from theme | Raw UI prop. Prefer theme.injectTheme. |
| onError | function | none | Called for catastrophic UI errors. |
Render And Lifecycle Hooks
| Property | Type | Description |
|----------|------|-------------|
| onBeforeRender(instance) | function | Called before the UI renders. Rapida uses this internally, then calls your handler. |
| onAfterRender(instance) | function | Called after the UI renders. |
| onViewPreChange(event, instance) | function | Called before the chat opens or closes. Can return a promise to delay the view change. |
| onViewChange(event, instance) | function | Called after the chat opens or closes. Rapida uses this to track docked/inline shell state, then calls your handler. |
| renderUserDefinedResponse | function | Renders custom user_defined response items. |
| renderCustomMessageFooter | function | Renders custom message footers. |
| renderWriteableElements | object | Renders writable slots. Rapida merges afterInputElement with its audio controls. |
Layout Modes
Floating (default)
A fixed-position panel with a launcher FAB. Click the button to open/close the chat.
window.chatbotConfig = {
layout: {
mode: "floating",
position: "bottom-right", // or "bottom-left", "top-right", "top-left"
},
launcher: {
isOn: true,
},
};Docked
Panel fixed to the side of the viewport. Pushes page content to make room.
window.chatbotConfig = {
layout: {
mode: "docked-right", // or "docked-left"
},
};Inline
Flows with the page content. Place the <div id="rapida-chat-app"> where you want it.
window.chatbotConfig = {
layout: {
mode: "inline",
},
};Features
- Text + Voice - type messages or speak with your assistant using WebRTC
- Markdown rendering - assistant responses render as rich Markdown
- Microphone device selector - choose input device during voice conversations
- Dark mode - automatic or manual light/dark theme switching
- Responsive - works on desktop and mobile browsers
- Single file - one
app.min.jsbundle, no external dependencies to load - Versioned CDN - pin to a specific version or always use the latest
Development
Prerequisites
- Node.js 20+
- npm
Setup
npm installCommands
npm start # Dev mode with watch (serves at webpack-dev-server)
npm run build # Production build -> dist/app.min.js
npm test # Run tests
npm run test:watch # Run tests in watch mode
npm run test:coverage # Run tests with coverage report
npm run storybook # Develop visual components in isolation
npm run build-storybook # Verify the static component catalogProject Structure
src/
├── index.tsx # Entry point, mounts React app
├── app/
│ ├── index.tsx # App root, creates VoiceAgent
│ └── pages/
│ ├── web-plugin-chat/ # Deployment loader
│ └── v3/ # Thin chat composition shell
├── adapters/
│ └── carbon/ # Carbon-specific DOM and style integration
├── components/
│ └── audio/ # Isolated voice UI, stories, and tests
├── contexts/
│ └── environment-context.tsx # Runtime configuration provider
├── hooks/
│ ├── use-chat-controller/ # Chat composition and Carbon config
│ ├── use-message-sync/ # Rapida-to-Carbon synchronization
│ └── use-audio-controls/ # Voice control state and actions
├── lib/
│ ├── layout/ # Pure layout resolution
│ ├── message-sync/ # Pure message mapping
│ └── voice-transcript/ # Pure transcript selection
├── configs/
│ └── index.ts # API base URL + constants
├── styles/
│ └── carbon.scss # Carbon imports and global overrides
├── types/
│ ├── globals.d.ts # Browser global declaration
│ └── widget.ts # Public widget configuration
└── __tests__/
├── helpers/ # Shared test adapters
└── setup.ts # Global Jest setupVisual components keep their stories and tests beside the implementation.
Business rules live in lib/ and do not depend on React. Carbon owns the chat
message UI; this repository only implements the Rapida integration and voice
controls. Carbon currently exposes no input-action slot, so the isolated
adapters/carbon/CarbonInputActionPortal.tsx adapter is the sole shadow-DOM
boundary.
CI/CD
On push to main:
- Build -
npm ci && npm run build - CDN - uploads
dist/app.min.jsto S3 with CloudFront invalidation - npm - publishes to npm as
@rapidaai/react-widget - Release - creates a GitHub release with a version tag
Pull requests run the CI pipeline (build + test) without deploying.
