Overview
CopilotChatInput is the primary text input and control surface for chat interactions. It provides a multi-line textarea that auto-grows up to a configurable maximum number of rows (default 5), action buttons for sending messages, voice transcription, and file attachment, and an optional tools menu for declarative command surfaces.
The component operates in three modes: "input" (default text entry), "transcribe" (replaces the textarea with an audio recorder), and "processing" (indicates background processing is underway). When text spans multiple rows, the layout stacks the textarea above the control row.
Import
Props
The current operating mode of the input component. - "input" -- Standard
text entry mode with textarea and send button. - "transcribe" -- Replaces
the textarea with the audio recorder component for voice input. -
"processing" -- Indicates that background processing is underway.
The current text value of the input. Use together with onChange for
controlled mode.
Callback invoked when the input text changes. Use together with value for
controlled mode.
When true, the textarea receives focus automatically on mount.
Whether the agent is currently executing. When true, the send button may be
replaced with a stop button, and the input may show a processing state.
Callback invoked when the user submits a message (by pressing Enter or clicking the send button). Receives the current text value.
Callback invoked when the user clicks the stop button during agent execution.
Callback invoked when the user initiates voice transcription. Typically
switches the component to "transcribe" mode.
Callback invoked when the user cancels an in-progress voice transcription.
Callback invoked when the user finishes voice transcription (text-only result).
Callback invoked when the user finishes voice transcription with an audio
recording. Receives the recorded audio as a Blob. Use this when you need to
send the raw audio for server-side speech-to-text processing.
Callback invoked when the user clicks the file attachment button. When not provided, the file attachment button is hidden.
Declarative configuration for a tools menu. Each entry is either a
ToolsMenuItem object or a separator string "-". See
ToolsMenuItem for the item structure. When not provided, the
tools menu button is hidden.
Optional render-prop function that receives layout state. The isMultiline
flag is true when the textarea content spans multiple rows, which triggers
the stacked layout (textarea above the control row).
Slots
All slot props follow the CopilotKit slot system: each accepts a replacement React component, a className string that is merged into the default component's classes, or a partial props object that extends the default component.
Slot for the text input area. Defaults to an auto-growing textarea that expands up to 5 rows (configurable via maxRows).
As a className:
<CopilotChatInput textArea="font-mono text-sm" />
Slot for the send/submit button. Defaults to an arrow icon button that submits the current message.
As a replacement component:
<CopilotChatInput
sendButton={({ onClick }) => (
<button
onClick={onClick}
className="bg-blue-500 text-white px-3 py-1 rounded"
>
Send
</button>
)}
/>
Slot for the button that initiates voice transcription. Only rendered when
onStartTranscribe is provided.
Slot for the button that cancels an in-progress voice transcription. Only
rendered during "transcribe" mode.
Slot for the button that completes voice transcription. Only rendered during
"transcribe" mode.
Slot for the file attachment button. Only rendered when onAddFile is
provided.
Slot for the audio recorder component displayed during "transcribe" mode.
Defaults to CopilotChatAudioRecorder.
ToolsMenuItem
The ToolsMenuItem type defines items in the tools menu. Items can trigger actions directly or contain nested submenus.
type ToolsMenuItem = { label: string } & (
| { action: () => void }
| { items: (ToolsMenuItem | "-")[] }
);
The display text for the menu item.
Callback invoked when the item is selected. Mutually exclusive with items.
Nested submenu items. Each entry is either another ToolsMenuItem or a
separator string "-". Mutually exclusive with action.
Separators
Use the string "-" as an array entry to render a visual separator between menu items:
toolsMenu={[
{ label: "Search", action: () => search() },
"-",
{ label: "Settings", action: () => openSettings() },
]}
Nested Submenus
Menu items with an items array render as expandable submenus:
toolsMenu={[
{
label: "Export",
items: [
{ label: "As PDF", action: () => exportPDF() },
{ label: "As CSV", action: () => exportCSV() },
"-",
{ label: "Print", action: () => printDoc() },
],
},
]}
CopilotChatAudioRecorder
A visual audio waveform component used during transcription mode. It displays a real-time waveform visualization of the microphone input and exposes an imperative API via ref.
Import
Imperative API
The component exposes the following imperative methods via React ref:
The current state of the recorder (e.g., "idle", "recording",
"stopped").
Begins audio recording and starts the waveform visualization.
Stops the current recording session.
Cleans up all resources (media stream, audio context, etc.) used by the recorder.
Usage
function CustomRecorder() {
const recorderRef = useRef(null);
return (
<div>
<CopilotChatAudioRecorder ref={recorderRef} />
<button onClick={() => recorderRef.current?.start()}>Record</button>
<button onClick={() => recorderRef.current?.stop()}>Stop</button>
</div>
);
}
Usage
Basic Chat Input
function ChatInput() {
const [value, setValue] = useState("");
return (
<CopilotChatInput
value={value}
onChange={setValue}
onSubmitMessage={(text) => {
sendMessage(text);
setValue("");
}}
autoFocus
/>
);
}
With Voice Transcription
function VoiceInput() {
const [mode, setMode] = useState<"input" | "transcribe">("input");
const [value, setValue] = useState("");
return (
<CopilotChatInput
mode={mode}
value={value}
onChange={setValue}
onSubmitMessage={(text) => sendMessage(text)}
onStartTranscribe={() => setMode("transcribe")}
onCancelTranscribe={() => setMode("input")}
onFinishTranscribeWithAudio={async (blob) => {
const text = await transcribeAudio(blob);
setValue(text);
setMode("input");
}}
/>
);
}
With Tools Menu
function InputWithTools() {
return (
<CopilotChatInput
onSubmitMessage={(text) => sendMessage(text)}
toolsMenu={[
{ label: "Search the web", action: () => triggerSearch() },
{ label: "Analyze data", action: () => triggerAnalysis() },
"-",
{
label: "Export",
items: [
{ label: "As PDF", action: () => exportPDF() },
{ label: "As Markdown", action: () => exportMarkdown() },
],
},
]}
/>
);
}
With Stop Button During Execution
function ChatInputWithAgent() {
const { agent } = useAgent();
return (
<CopilotChatInput
isRunning={agent.isRunning}
onSubmitMessage={(text) => {
agent.addMessage({
role: "user",
content: text,
id: crypto.randomUUID(),
});
agent.runAgent();
}}
onStop={() => agent.abortRun()}
autoFocus
/>
);
}
Custom Layout with Children Render Prop
function AdaptiveInput() {
return (
<CopilotChatInput onSubmitMessage={(text) => sendMessage(text)}>
{({ isMultiline }) => (
<div
className={
isMultiline ? "border-2 border-blue-300 rounded-xl p-2" : ""
}
>
{isMultiline && (
<div className="text-xs text-gray-400 mb-1">Multi-line mode</div>
)}
</div>
)}
</CopilotChatInput>
);
}
Styled Slots
function StyledInput() {
return (
<CopilotChatInput
onSubmitMessage={(text) => sendMessage(text)}
textArea="font-mono text-sm bg-gray-50 rounded-lg"
sendButton="bg-green-500 hover:bg-green-600 text-white rounded-full"
/>
);
}
Behavior
- Auto-Growing Textarea: The default textarea automatically expands as the user types, up to a maximum of 5 rows. After reaching the maximum, the textarea becomes scrollable.
- Layout Stacking: When the input text spans multiple rows, the layout switches from inline (textarea and buttons side by side) to stacked (textarea above the control row containing the action buttons).
- Mode Switching: Setting
modeto"transcribe"replaces the textarea with theaudioRecorderslot component. The transcription control buttons (cancelTranscribeButton,finishTranscribeButton) replace the standard send button. - Controlled and Uncontrolled: The component supports both controlled mode (via
valueandonChange) and uncontrolled mode (internal state management). - Tools Menu: The
toolsMenuprop enables a declarative menu with support for flat items, separators ("-"), and nested submenus. The menu button is only rendered whentoolsMenuis provided. - Slot System: Each slot prop accepts three forms -- a replacement component, a className string merged into the default, or a partial props object that extends the default component's props.
Related
CopilotChatView-- Higher-level chat view that composes this componentCopilotChatAudioRecorder-- Audio recorder used during transcription modeuseCopilotChatConfiguration-- Provider for localized input labels