React Hooks
@elaras/react-chat provides a useChat() hook and ElarasProvider for building chat UIs in React. It handles session management, streaming, and state internally so you can focus on your UI.
Installation
npm install @elaras/react-chat
Setup — ElarasProvider
Wrap your app (or just the part that needs the chatbot) with ElarasProvider:
import {ElarasProvider} from '@elaras/react-chat'; function App() { return ( <ElarasProvider chatbotKey="cbt_your_key_here"> <YourApp /> </ElarasProvider> ); }
ElarasProvider props
| Prop | Type | Required | Description |
|---|---|---|---|
chatbotKey | string | Yes | Your public chatbot key (cbt_...) |
apiUrl | string | No | Override the API base URL (defaults to https://api.elaras.ai/api) |
children | ReactNode | Yes | Your component tree |
useChat()
Call useChat() inside any component that is a descendant of ElarasProvider:
import {useChat} from '@elaras/react-chat'; function ChatWidget() { const {messages, send, status, isTyping, error, clearSession} = useChat(); // ... }
Return values
| Value | Type | Description |
|---|---|---|
messages | Message[] | All messages in the current session (user and assistant) |
send | (text: string) => void | Send a message. Automatically appends the user message and streams the AI response |
status | ChatStatus | Current state of the chat |
isTyping | boolean | true while waiting for the first token (shows the typing indicator) |
error | string | null | Error message if status === 'error', otherwise null |
clearSession | () => void | Clear the session and start a fresh conversation |
Message type
interface Message { id: string; // Client-side UUID (for React key) role: 'user' | 'assistant'; content: string; // Full content (grows as tokens arrive during streaming) messageId?: number; // Server-assigned ID (set when 'done' event arrives) createdAt: Date; }
ChatStatus type
type ChatStatus = 'idle' | 'typing' | 'streaming' | 'error';
| Status | Description |
|---|---|
idle | No active request — ready to send |
typing | Message sent, waiting for the first token from the AI |
streaming | Receiving tokens — the last assistant message is growing |
error | The last request failed — error contains the message |
Tip: Use isTyping (which is status === 'typing') to show a typing indicator bubble before the first token arrives. Once status === 'streaming' the tokens are rendering in the last message directly.
Full example
import React, {useState, useRef, useEffect} from 'react'; import {ElarasProvider, useChat} from '@elaras/react-chat'; // Provider — put this at the top of your tree export function ChatApp() { return ( <ElarasProvider chatbotKey="cbt_your_key_here"> <ChatUI /> </ElarasProvider> ); } // Chat UI component function ChatUI() { const {messages, send, status, isTyping, error, clearSession} = useChat(); const [input, setInput] = useState(''); const bottomRef = useRef<HTMLDivElement>(null); // Scroll to bottom when messages change useEffect(() => { bottomRef.current?.scrollIntoView({behavior: 'smooth'}); }, [messages]); function handleSubmit(e: React.FormEvent) { e.preventDefault(); if (!input.trim() || status === 'typing' || status === 'streaming') return; send(input.trim()); setInput(''); } return ( <div className="chat-container"> {/* Header */} <div className="chat-header"> <h2>Chat</h2> <button onClick={clearSession} disabled={status !== 'idle'}> New conversation </button> </div> {/* Messages */} <div className="chat-messages"> {messages.map((msg) => ( <div key={msg.id} className={`message message--${msg.role}`}> {msg.content} </div> ))} {/* Typing indicator — shown while waiting for first token */} {isTyping && ( <div className="message message--assistant message--typing"> <span className="dot" /><span className="dot" /><span className="dot" /> </div> )} {/* Error state */} {error && ( <div className="message message--error"> {error} </div> )} <div ref={bottomRef} /> </div> {/* Input */} <form onSubmit={handleSubmit} className="chat-input-row"> <input value={input} onChange={(e) => setInput(e.target.value)} placeholder="Type a message..." disabled={status === 'typing' || status === 'streaming'} /> <button type="submit" disabled={!input.trim() || status === 'typing' || status === 'streaming'} > Send </button> </form> </div> ); }
Accessing the SDK directly
If you need to call SDK methods not exposed by useChat() (such as submitLead or submitFeedback), use the useElaras() hook to get the underlying ChatClient instance and the current session ID:
import {useElaras} from '@elaras/react-chat'; function LeadForm() { const {client, sessionId} = useElaras(); async function handleSubmit(email: string, name: string) { await client.submitLead(sessionId, {email, name}); } // ... }
useElaras() returns { client, sessionId, resetSession } — the same values the provider manages internally.
TypeScript
Both @elaras/react-chat and @elaras/chat-sdk are written in TypeScript and ship full type definitions. No @types/ package needed.
import type {Message, ChatStatus, UseChatReturn} from '@elaras/react-chat'; import type {ChatbotConfig, ChatMessage, StreamEvent} from '@elaras/chat-sdk';
