Component
Controlled mode

ChatInterface

Fully controlled mode where your app owns data fetching, state transitions, and action semantics.

What fully controlled means

Why choose this mode

Use ChatInterface when your app already has a state architecture, custom persistence rules, or backend orchestration that should stay centralized.

Full working example

App.tsx
import React from 'react';
import { ChatInterface } from '@jazzmine-ui/react';
import type { Chat, Context, Message } from '@jazzmine-ui/react';
import '@jazzmine-ui/react/styles';

export function App() {
  // App-owned state: ChatInterface only renders what you pass.
  const [messages, setMessages] = React.useState<Message[]>([]);
  const [chats] = React.useState<Chat[]>([]);
  const [activeChatId, setActiveChatId] = React.useState<string>();
  const [isLoading, setIsLoading] = React.useState(false);

  const onSend = async (text: string, contexts?: Context[]) => {
    setMessages((prev) => [
      ...prev,
      { id: crypto.randomUUID(), text, sender: 'user', timestamp: new Date().toISOString() },
    ]);

    setIsLoading(true);
    try {
      // Forward optional contexts to backend when available.
      console.log('Forward selected contexts to backend:', contexts);
      const reply = `Echo: ${text}`;
      setMessages((prev) => [
        ...prev,
        {
          id: crypto.randomUUID(),
          text: reply,
          sender: 'assistant',
          timestamp: new Date().toISOString(),
        },
      ]);
    } finally {
      setIsLoading(false);
    }
  };

  const onNewChat = () => {
    console.log('Create a new chat in your backend, then update chats state.');
  };

  const onSelectChat = (chatId: string) => {
    setActiveChatId(chatId);
    console.log('Load messages for chat:', chatId);
  };

  const onDeleteChat = (chatId: string) => {
    console.log('Delete chat in backend:', chatId);
    if (activeChatId === chatId) {
      setActiveChatId(undefined);
      setMessages([]);
    }
  };

  return (
    <div style={{ height: '100vh' }}>
      <ChatInterface
        chats={chats} /* Required: conversations shown in sidebar */
        activeChatId={activeChatId} /* Optional: currently active conversation id */
        messages={messages} /* Required: feed data for the main panel */
        onSend={onSend} /* Required: composer send action */
        onNewChat={onNewChat} /* Required: new-chat action */
        onSelectChat={onSelectChat} /* Required: sidebar selection action */
        onDeleteChat={onDeleteChat} /* Optional: enables delete action */
        isLoading={isLoading} /* Optional: assistant loading state */
        defaultMessage="Welcome! Ask me anything to get started." /* Optional: empty feed message */
      />
    </div>
  );
}

Context forwarding with onSend

The send callback receives selected context snippets as the second argument. Forward those contexts to your backend if your model supports retrieval-augmented or grounded responses.

ChatInterface props

PropTypeRequiredDefaultDescription
messagesMessage[]Yes-Current message list.
chatsChat[]Yes-Sidebar conversation list.
onSend(text: string, contexts?: Context[]) => voidYes-Send handler; receives selected context snippets when present.
onNewChat() => voidYes-New chat action.
onSelectChat(chatId: string) => voidYes-Active chat selection.
activeChatIdstringNo-Active conversation id.
assistantNamestringNo'AI Assistant'Assistant display name.
onRenameChat(chatId: string, newTitle?: string) => voidNo-Rename conversation action.
onDeleteChat(chatId: string) => voidNo-Delete conversation action.
onSearchClick() => voidNo-Opens external conversation search flow.
onLoadMore() => voidNo-Load-more trigger for infinite conversation lists.
hasMorebooleanNofalseIndicates additional chat pages are available.
isLoadingChatsbooleanNofalseSidebar list loading indicator.
isSearchOpenbooleanNofalseControls sidebar search visibility.
searchQuerystringNo''Sidebar search query value.
onSearchQueryChange(query: string) => voidNo-Sidebar search input handler.
isLoadingbooleanNofalseMessage send/load state.
loadingTextstringNo''Assistant status text while loading.
loadingVariant'text-and-dots' | 'dots-only'No'text-and-dots'Loading indicator style.
placeholderstringNo'Type your message...'Input placeholder text.
classNamestringNo''Root class override.
defaultMessagestringNo''Empty-state assistant message.