@velnai/chat-react
v0.1.1
Published
Drop the Velnai web-chat widget into any React app. Provider + hook around the existing iframe loader.
Downloads
228
Maintainers
Readme
@velnai/chat-react
Drop the Velnai web-chat widget into any React app.
npm install @velnai/chat-reactUsage
Mount the Provider once at your app root:
import { VelnaiChatProvider } from '@velnai/chat-react'
export default function RootLayout({ children }) {
return (
<VelnaiChatProvider
publicKey="wac_xxx"
visitorAttrs={{ email: user.email, plan: user.plan }}
onReady={() => console.log('chat ready')}
>
{children}
</VelnaiChatProvider>
)
}The bubble appears in the corner of every page automatically.
Control the widget from anywhere via the hook:
import { useVelnaiChat } from '@velnai/chat-react'
function LogoutButton() {
const { reset } = useVelnaiChat()
return <button onClick={reset}>Log out</button>
}
function OpenChatButton() {
const { open } = useVelnaiChat()
return <button onClick={open}>Need help?</button>
}Props
| Prop | Type | What it does |
|---|---|---|
| publicKey | string | The agent's public key (wac_xxx). |
| visitorAttrs | Record<string, string \| number \| boolean \| null> | Visitor identity — max 16 keys. Re-applied on prop change. |
| widgetBase | string | Override the widget host. Default https://widget.velnai.com. |
| onReady | () => void | Fires once the bubble has loaded. |
| onOpen | () => void | Fires when the visitor opens the panel. |
| onClose | () => void | Fires when the visitor closes the panel. |
Hook API
useVelnaiChat() returns:
| Method | Behavior |
|---|---|
| identify(attrs) | Merge visitor attributes mid-session. |
| reset() | Clear all visitor attributes (e.g. after logout). |
| getAttrs() | Snapshot of current attributes. |
| open() | Programmatically expand the panel. |
| close() | Programmatically collapse to the bubble. |
How it works
The Provider injects the official widget boot script (https://widget.velnai.com/widget/boot.js) on mount. The boot script creates a sandboxed iframe in the corner of the page — same iframe every visitor sees, same renderer as the script-tag embed. The Provider just wires React props and hook callbacks into the existing postMessage channel.
Mount the Provider once. The boot script is injected once per page; mounting two Providers on the same page is harmless (script-tag guard) but you only get one widget instance regardless.
Why iframe instead of a native React port?
The widget has 30+ features (signature, file upload, voice messages, RTC voice calls, ticket forms, conditional logic, theming) that would need to be re-implemented and kept in sync if we shipped a native renderer. iframe means new features land in your app the day they ship on the web — zero work on your side.
License
MIT
