Skip to Content

React

@oshara/voice-sdk/react is a thin layer over the headless core. react and react-dom are optional peer dependencies (>= 17).

For how this fits alongside the other creation methods, see Creating an Agent → React.

useVoiceAgent(config)

Creates and owns a client for the component’s lifetime, subscribes to its events, and returns reactive state + bound actions.

import { useVoiceAgent } from "@oshara/voice-sdk/react"; function VoicePanel() { const { ready, connected, orb, statusLabel, callStatus, muted, transcript, activeForm, formErrors, formSubmitting, start, end, toggleMute, sendText, updateFormValues, submitForm, stepForm, closeForm, } = useVoiceAgent({ agentSlug: "support-bot" }); if (!ready) return <p>Loading…</p>; return ( <div> <button onClick={connected ? end : start}> {connected ? "End" : "Start"} </button> {connected && ( <button onClick={toggleMute}>{muted ? "Unmute" : "Mute"}</button> )} <p>{orb}{statusLabel ? ` — ${statusLabel}` : ""}</p> <ul> {transcript.map((t) => ( <li key={t.key} className={t.isFinal ? "final" : "interim"}> <b>{t.role}:</b> {t.text} </li> ))} </ul> {activeForm && ( <form onSubmit={(e) => { e.preventDefault(); submitForm(); }}> {/* render activeForm.definition fields; call updateFormValues onChange */} {formErrors.map((er) => <small key={er.name}>{er.message}</small>)} <button type="submit" disabled={formSubmitting}>Submit</button> </form> )} </div> ); }

Returned state

client, ready, orb, statusLabel, callStatus, connected, muted, appearance, audio, transcript (TranscriptItem[]), activeForm ({ definition, values, stepIndex } | null), formErrors, formSubmitting.

Returned actions

start, end, toggleMute, sendText, updateFormValues, submitForm, stepForm, closeForm. Need more? client exposes the full API.

The config is read once on mount. Changing it later does not recreate the client — to switch agents, remount with a key:

<VoicePanel key={agentSlug} />

<VoiceWidget> — prebuilt UI

Drops the full widget UI into a container div. The DOM UI layer is dynamically imported, so a headless-only app that never renders it doesn’t pay for it in the bundle.

import { VoiceWidget } from "@oshara/voice-sdk/react"; <VoiceWidget config={{ agentSlug: "support-bot" }} inline openChat />;

Props: config: VoiceAgentConfig, plus inline, openChat, closeButtonHide, className, style.

Next.js / SSR

The SDK touches browser APIs, so render these on the client only:

  • App Router: put "use client" at the top of the component file.
  • Pages Router: load with next/dynamic and { ssr: false }.
"use client"; import { VoiceWidget } from "@oshara/voice-sdk/react"; export default function Widget() { return <VoiceWidget config={{ agentSlug: "support-bot" }} />; }
Last updated on