Build a Chat Flow
This guide covers the core conversation model behind react-actions-chat.
The best runnable reference in this repo is examples/qa-bot/App.tsx.
Core Pieces
Chatrenders the transcript, persistent buttons, and shared input field.InputMessageis the shape you pass intoinitialMessagesoruseChatStore().addMessage(...).MessageButtondescribes an action shown under an assistant message.userResponseCallbacklets an assistant message react to the next user submission.
Start With Seed Messages
import { Chat, type InputMessage } from 'react-actions-chat';
import 'react-actions-chat/styles';
const initialMessages: readonly InputMessage[] = [
{
type: 'other',
content: 'Hello! I can help with orders, billing, or shipping.',
},
];
export function App() {
return <Chat initialMessages={initialMessages} />;
}Use type: 'other' for assistant-side messages and type: 'self' for user-side messages. For the full message shape, see InputMessage. In most apps you add assistant messages yourself and let the component add user messages when the shared input is submitted.
Add Action Buttons
import { Chat, createButton, useChatStore } from 'react-actions-chat';
function addWelcomeMessage() {
useChatStore.getState().addMessage({
type: 'other',
content: 'What do you need help with?',
buttons: [
createButton({
label: 'Billing help',
onClick: () => {
useChatStore.getState().addMessage({
type: 'other',
content: 'I can explain charges, invoices, or renewals.',
});
},
}),
],
});
}Each new message clears buttons from older messages, which keeps the active step focused on the current part of the conversation.
Handle Free-Form Follow-Ups
userResponseCallback is the hook that turns the shared input into a simple conversation loop.
useChatStore.getState().addMessage({
type: 'other',
content: 'Ask me a question about your order.',
userResponseCallback: () => {
const messages = useChatStore.getState().getMessages();
const lastSelfMessage = [...messages]
.reverse()
.find(message => message.type === 'self');
if (!lastSelfMessage) {
return;
}
useChatStore.getState().addMessage({
type: 'other',
content: `You asked: ${lastSelfMessage.rawContent}`,
});
},
});Use rawContent when you need the real submitted value. That matters for flows such as password inputs, where the visible transcript may be masked. See Message and useChatStore for the stored message shape and common retrieval patterns.
Advanced State Access
useChatStore is exported for advanced flows:
addMessageandaddMessagesappend assistant or seeded messagesgetMessagesandgetPreviousMessageinspect the current transcriptsetLoadingandclearLoadingdrive async loading statesclearMessages,clearButtons, and related helpers reset or trim the conversation
Reach for the store when you need app-driven branching or async coordination. For straightforward static UIs, initialMessages plus createButton is often enough.