gridland
Components

Chat

A vertical chat interface with messages, tool calls, streaming, and text input

A self-contained vertical chat interface that combines message display, tool call status cards, streaming text, a loading indicator, and a PromptInput. SDK-agnostic — the consumer passes messages and handles submission.

Chat
?

Run demo

Terminal
bunx @gridland/demo chat
Terminal
curl -fsSL https://raw.githubusercontent.com/thoughtfulllc/gridland/main/scripts/run-demo.sh | bash -s chat

Installation

bunx shadcn@latest add @gridland/chat

Usage

import { ChatPanel } from "@/components/ui/chat"
<ChatPanel
  messages={[
    { id: "1", role: "user", content: "Hello!" },
    { id: "2", role: "assistant", content: "Hi there!" },
  ]}
  onSendMessage={(text) => console.log(text)}
/>

Examples

With Status

Use the status prop to drive loading and streaming states. This takes precedence over the legacy isLoading prop.

With status
<ChatPanel
  messages={messages}
  status="streaming"
  streamingText={partialText}
  onSendMessage={handleSend}
  onStop={handleStop}
/>

Tool Calls

Display active tool call status cards between messages and the input.

With tool calls
<ChatPanel
  messages={messages}
  activeToolCalls={[
    { id: "1", title: "Reading file", status: "completed" },
    { id: "2", title: "Running tests", status: "in_progress" },
  ]}
  onSendMessage={handleSend}
/>

Custom Colors

Override the default prefix colors for user and assistant messages.

Custom colors
<ChatPanel
  messages={messages}
  userColor="#05FFA1"
  assistantColor="cyan"
  promptColor="#05FFA1"
  onSendMessage={handleSend}
/>

With AI SDK

Vercel AI SDK
const { messages, status, sendMessage, stop } = useChat({ api: "/api/chat" })

<ChatPanel
  messages={messages.map(m => ({ id: m.id, role: m.role, content: m.parts?.find(p => p.type === "text")?.text ?? "" }))}
  status={status}
  onSendMessage={(text) => sendMessage({ text })}
  onStop={stop}
/>

Controls

  • Enter: Submit message
  • Escape: Stop generation (calls onStop during streaming)

API Reference

ChatPanel

PropTypeDefaultDescription
messagesChatMessage[]-Array of messages to display
streamingTextstring""Partial streaming text from assistant
statusChatStatus-AI chat status. Takes precedence over isLoading.
isLoadingbooleanfalseWhether the assistant is processing. Ignored when status is provided.
activeToolCallsToolCallInfo[][]Active tool call status cards
onSendMessage(text: string) => void-Called when the user submits a message
onStop() => void-Called on Escape during streaming
placeholderstring"Type a message..."Input placeholder text
promptCharstring"> "Prompt string before user input
promptColorstringtheme.secondaryColor of the prompt
userColorstringtheme.secondaryColor of user message > prefix
assistantColorstringtheme.primaryColor of assistant message < prefix
loadingTextstring"Thinking..."Loading indicator text
useKeyboard(handler: (event: any) => void) => void-Keyboard hook from @opentui/react

ChatMessage

FieldTypeDescription
idstringUnique identifier
role"user" | "assistant"Message sender role
contentstringMessage text content
toolCallsToolCallInfo[]?Tool calls associated with this message

ToolCallInfo

FieldTypeDescription
idstringUnique identifier
titlestringDisplay name of the tool call
status"pending" | "in_progress" | "completed" | "failed"Current status
resultstring?Result text from the tool call

ChatStatus

ValueDescription
"ready"Input enabled, accepts user input
"submitted"Shows loading indicator, input disabled
"streaming"Shows streaming text, input disabled, Escape calls onStop
"error"Input enabled, shows error state