Widget Element
<voice213-agent>: a ready-made call button and panel, styled to your brand
<voice213-agent> is a complete call button and panel in one HTML tag. It shows a floating Talk to us button that opens a panel with the agent's picture, live status, timer, transcript, mute and hang-up. It works on any site and with any framework: plain HTML, React, Vue, Svelte, Angular.
Add it
With a bundler:
npm install @voice213/agent-clientimport "@voice213/agent-client/widget"; // registers <voice213-agent><voice213-agent agent-id="k3x9m2p7q4wz"></voice213-agent>Without a build step:
<script src="https://cdn.jsdelivr.net/npm/@voice213/agent-client@0.2.0/dist/voice213.global.js" integrity="sha384-uC0Le1b+8b6nZJG677oFQhHDxkXIBxBpQlUAAagUB87AO8yyCfYNurb87rOCGVKw" crossorigin="anonymous" defer></script>
<voice213-agent agent-id="k3x9m2p7q4wz"></voice213-agent>The tag pins a release, and integrity makes the browser refuse the file if it ever differs from that release by a single byte, so a compromised CDN or package can't run code on your site. To upgrade, change the version and the integrity value together: each release's tag is in the package's README on npm and its changelog.
The element reads the agent's public profile (name, picture, colours, language, greeting) and builds itself from it. If the agent isn't published, nothing appears, and the reason is logged in the console.
Attributes
| Attribute | Default | |
|---|---|---|
agent-id | (required) | The agent's public id |
variant | floating | floating: a button in a corner that opens the panel. inline: the panel in the page flow, always open, for a contact page or a help center. |
position | right | left puts the floating button in the bottom-left corner |
label | "Talk to us", in the panel's language | The floating button's text |
accent | The agent's accent colour | The button colour, as #RRGGBB |
lang | From the agent's language | The panel's language: ar (right to left), fr or en |
open | Absent | Present: the floating panel starts open |
base-url | https://api.voice213.com | The API's address |
Change any attribute at any time and the element follows. Change agent-id and it loads the new agent.
<voice213-agent agent-id="k3x9m2p7q4wz" variant="inline" lang="ar" accent="#0E7C66"></voice213-agent>Style it
The element draws itself in its own shadow root, so your site's CSS can't break it. Customise it with CSS variables and parts:
voice213-agent {
--voice213-accent: #0e7c66; /* buttons (overrides the accent attribute) */
--voice213-font: "Cairo", system-ui, sans-serif;
--voice213-offset: 24px; /* distance of the floating button from the corner */
--voice213-z-index: 1000;
}
voice213-agent::part(fab) { box-shadow: none; }
voice213-agent::part(panel) { border-radius: 16px; }
voice213-agent::part(transcript) { max-height: 240px; }The parts are fab (the floating button), panel, start, mute, end and transcript. The panel follows the visitor's light or dark mode.
Events
The element dispatches DOM events that bubble out of the shadow root. Each event's detail carries the payload of the matching AgentCall event:
| Event | detail |
|---|---|
voice213-status | "connecting", "connected", "ended" or "error" |
voice213-ready | { conversationId, maxSeconds, agent } |
voice213-message | { id, role, text, at }: a completed turn or tool run |
voice213-ended | { reason, durationSeconds, conversationId } |
voice213-error | A Voice213Error, with its code |
document.querySelector("voice213-agent").addEventListener("voice213-ended", (event) => {
gtag("event", "agent_call", { duration: event.detail.durationSeconds });
});Control it from code
const widget = document.querySelector("voice213-agent");
widget.open(); // open the panel
await widget.start(); // open it and start a call (from a click)
await widget.end(); // hang up
widget.close(); // close the panel (and hang up)
widget.call; // the AgentCall behind it: state, levels, eventsstart() must run from a user gesture, like any call: for example, from your own "Call us" button elsewhere on the page.
In React
"use client";
import { useEffect, useRef } from "react";
import "@voice213/agent-client/widget";
export function Widget() {
const widget = useRef(null);
useEffect(() => {
const element = widget.current;
const onEnded = (event) => console.log("call ended", event.detail);
element.addEventListener("voice213-ended", onEnded);
return () => element.removeEventListener("voice213-ended", onEnded);
}, []);
return <voice213-agent ref={widget} agent-id="k3x9m2p7q4wz" variant="inline" />;
}Importing the widget on the server (Next.js renders Client Components there too) is harmless: the element registers itself only in the browser. To build your own interface in React, use useAgentCall.
Another tag name
To register the element under another name, for example to run two versions side by side:
import { defineVoice213Agent } from "@voice213/agent-client/widget";
defineVoice213Agent("shop-voice-agent");The script-tag widget
The one-line widget served by Voice213 (voice213.com/widget/agent.js) needs no npm package and is designed from the dashboard: it can offer a call, a text chat or both, with a greeting bubble and your site's own buttons opening it. Use <voice213-agent> when you want to place it inline, style it, listen to its events, or bundle it with your site.
Was this page helpful?