Raw markdown

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

PropTypeRequiredDescription
chatbotKeystringYesYour public chatbot key (cbt_...)
apiUrlstringNoOverride the API base URL (defaults to https://api.elaras.ai/api)
childrenReactNodeYesYour 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

ValueTypeDescription
messagesMessage[]All messages in the current session (user and assistant)
send(text: string) => voidSend a message. Automatically appends the user message and streams the AI response
statusChatStatusCurrent state of the chat
isTypingbooleantrue while waiting for the first token (shows the typing indicator)
errorstring | nullError message if status === 'error', otherwise null
clearSession() => voidClear 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';
StatusDescription
idleNo active request — ready to send
typingMessage sent, waiting for the first token from the AI
streamingReceiving tokens — the last assistant message is growing
errorThe 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';