Overview
@akapulu/react-ui is the higher-level React UI package in the Akapulu Web SDK.
It is built on top of @akapulu/react and provides a prebuilt conversation interface for React apps.
Installation
Main export
The main export isAkapuluConversation.
Main responsibility
@akapulu/react-ui is responsible for rendering a ready-made conversation UI with:
- video layout
- transcript UI
- loading and error states
- current node display
- tool event surfaces
- built-in call controls
How it fits in your app
In a typical React app:AkapuluProviderfrom@akapulu/reactpoints at your local routes.- Your routes call Akapulu through
@akapulu/server. AkapuluConversationrenders the higher-level conversation UI on top of that session state.
connectBody, custom UI without this package, and post-call APIs).
When to use this package
Use@akapulu/react-ui when you want:
- the fastest React integration
- a prebuilt conversation UI
- styling and rendering customization without building every surface from scratch
@akapulu/react directly.
Minimal example
Styling AkapuluConversation
@akapulu/react-ui supports slot-level customization via:
classNamefor the rootclassesfor slot class namesstylesfor slot inline style overrides
Example 1: Slot key overrides (classes + styles)
Use slot keys when you want to target specific UI parts directly from React props.
Example 2: Default class overrides (global CSS)
Use built-in default classes when you want to apply theme-like global styles from CSS.Example 3: data-slot overrides (stable CSS selectors)
Use data-slot selectors when you want explicit, inspectable selectors in DevTools.
Slot map
Each slot has both a default class and adata-slot marker so users can inspect and target it in DevTools without guessing.
Layout
| Slot key | What it targets | Default class | data-slot value |
|---|---|---|---|
container | Outer wrapper for the whole conversation UI | akapulu-conversation | container |
title | Top heading text | akapulu-title | title |
connectedLayout | Main connected-state grid wrapper | akapulu-connected-layout | connected-layout |
startButton | Idle/error state start-call button | akapulu-start-button | start-button |
Loading
| Slot key | What it targets | Default class | data-slot value |
|---|---|---|---|
loadingContainer | Wrapper for loading state UI | akapulu-loading-container | loading-container |
loadingSpinner | Loading spinner element | akapulu-loading-spinner | loading-spinner |
loadingLabel | Loading headline text (e.g. Connecting…) | akapulu-loading-label | loading-label |
loadingProgressTrack | Progress bar background track | akapulu-loading-progress-track | loading-progress-track |
loadingProgressFill | Progress bar filled portion | akapulu-loading-progress-fill | loading-progress-fill |
loadingStatusText | Detailed status text under progress bar | akapulu-loading-status-text | loading-status-text |
Error modal
| Slot key | What it targets | Default class | data-slot value |
|---|---|---|---|
errorModalBackdrop | Full-screen modal overlay behind error card | akapulu-error-modal-backdrop | error-modal-backdrop |
errorModalCard | Error modal content card | akapulu-error-modal-card | error-modal-card |
Tool events
| Slot key | What it targets | Default class | data-slot value |
|---|---|---|---|
toolToast | Floating toast/card for tool activity | akapulu-tool-toast | tool-toast |
Video + controls
| Slot key | What it targets | Default class | data-slot value |
|---|---|---|---|
videoPane | Video column container | akapulu-video-pane | video-pane |
videoSurface | Primary remote/bot video surface | akapulu-video-surface | video-surface |
botStateBadge | Speaking/listening/idle badge on video | akapulu-bot-state-badge | bot-state-badge |
pip | Local picture-in-picture preview tile | akapulu-pip | pip |
waitingVideo | Placeholder shown before video is available | akapulu-waiting-video | waiting-video |
controlMic | In-call mic button (video mode) | akapulu-control-mic | control-mic |
controlCam | In-call camera button (video mode) | akapulu-control-cam | control-cam |
controlEnd | In-call hang-up button (video mode) | akapulu-control-end | control-end |
Transcript
| Slot key | What it targets | Default class | data-slot value |
|---|---|---|---|
transcriptPane | Transcript column container | akapulu-transcript-pane | transcript-pane |
transcriptContainer | Scrollable transcript box | akapulu-transcript-container | transcript-container |
transcriptHeader | Transcript header row | akapulu-transcript-header | transcript-header |
nodeChip | Current node chip in transcript header | akapulu-node-chip | node-chip |
transcriptRowUser | User transcript row/bubble | akapulu-transcript-row-user | transcript-row-user |
transcriptRowBot | Bot transcript row/bubble | akapulu-transcript-row-bot | transcript-row-bot |
Behavior customization (handlers + custom elements)
Beyond styles,@akapulu/react-ui lets you customize behavior and rendering for transcript and tool events directly on AkapuluConversation.
Built-in handler props on AkapuluConversation
transcriptFilter(entry)to hide transcript rowsrenderTranscriptEntry(entry)to render transcript rows with your own JSXonToolEvent(tool)to run side effects when a tool event arrivesrenderToolEvent(tool)to replace the default tool toast elementtoolEventTimeoutMsto control how long the tool toast stays visible
toolEventTimeoutMs behavior:
- default:
4000 - pass a number to customize the auto-hide timeout
- pass
nullto disable auto-hide
TranscriptEntry shape (entry):
| Field | Type | Description |
|---|---|---|
id | string | Stable transcript row id |
speaker | "user" | "bot" | Who produced this transcript chunk |
text | string | Transcript text |
timestamp | string | Event timestamp |
isFinal | boolean | Whether this transcript row is finalized |
NormalizedToolEvent shape (tool) by tool type:
RAG tool event
| Field | Type | Description |
|---|---|---|
messageType | "RAG" | RAG tool event |
functionName | string | RAG function/tool name |
summary | string | "RAG tool called" |
query | string | undefined | Query text |
vision tool event
| Field | Type | Description |
|---|---|---|
messageType | "vision" | Vision tool event |
functionName | string | Vision function/tool name |
summary | string | "Vision tool called" |
http tool event
| Field | Type | Description |
|---|---|---|
messageType | "http" | HTTP tool event |
functionName | string | HTTP function/tool name |
summary | string | "HTTP endpoint called" |
argsJson | string | undefined | Pretty JSON string of body |
body | Record<string, unknown> | Outgoing HTTP request payload fields |
Handling all conversation events while keeping prebuilt UI
For full event handling (node changes, bot speaking state, transcript updates, tool calls, and timeout), add a small sibling listener component that usesuseAkapuluEvents from @akapulu/react.
event.type:
status_changed
| Field | Type | Description |
|---|---|---|
type | "status_changed" | Discriminator |
status | "idle" | "connecting" | "connected" | "disconnecting" | "ended" | "error" | Session lifecycle state |
bot_speaking_state_changed
| Field | Type | Description |
|---|---|---|
type | "bot_speaking_state_changed" | Discriminator |
speakingState | "idle" | "speaking" | "listening" | Bot speaking/listening state |
node_changed
| Field | Type | Description |
|---|---|---|
type | "node_changed" | Discriminator |
node | { key: string; label: string } | null | Current flow node |
tool_event
| Field | Type | Description |
|---|---|---|
type | "tool_event" | Discriminator |
tool | NormalizedToolEvent | Normalized tool event payload |
transcript_updated
| Field | Type | Description |
|---|---|---|
type | "transcript_updated" | Discriminator |
transcript | TranscriptEntry | Updated transcript row |
call_ready
| Field | Type | Description |
|---|---|---|
type | "call_ready" | Call reached ready state |
timeout
| Field | Type | Description |
|---|---|---|
type | "timeout" | Discriminator |
reason | "duration_limit_reached" | "participant_join_timeout" | Timeout reason from backend |

