showcase/shell-docs/src/content/reference/angular/components/CopilotChatInput.mdx
CopilotChatInput is the input area of the chat. It renders the textarea, the send button, an optional tools menu, an add-file button, and the audio transcription controls. It has three modes: "input" (the default textarea), "transcribe" (records audio and shows transcription controls), and "processing" (disables the textarea and send button while the agent runs).
CopilotChatInput requires a parent injector to provide ChatState. It reads that state through injectChatState and wires submission, value changes, transcription, and file uploads to it. Its outputs fire in addition to that built-in behavior, so you can observe interactions without disabling them.
CopilotChatInput is a standalone component with the selector copilot-chat-input. The example below provides the required ChatState. Use CopilotChat when you want CopilotKit to manage this state for you.
import { Component, forwardRef, signal } from "@angular/core";
import { ChatState, CopilotChatInput } from "@copilotkit/angular";
@Component({
selector: "app-chat",
standalone: true,
imports: [CopilotChatInput],
providers: [
{
provide: ChatState,
useExisting: forwardRef(() => ChatComponent),
},
],
template: `
<copilot-chat-input
[autoFocus]="true"
(submitMessage)="onSubmit($event)"
/>
`,
})
export class ChatComponent extends ChatState {
readonly inputValue = signal("");
submitInput(value: string) {
// Send the message through your chat state owner.
console.log("user submitted:", value);
}
changeInput(value: string) {
this.inputValue.set(value);
}
}
Each interactive piece can be replaced with a component class (*Component). Templates for the same slots are read from content projection.
These events fire in addition to the input's built-in handling, so you can observe interactions without replacing default behavior.
<PropertyReference name="submitMessage" type="string"> Emitted with the trimmed message text when the user sends a message (Enter without Shift, or the send button). </PropertyReference> <PropertyReference name="valueChange" type="string"> Emitted whenever the textarea value changes. </PropertyReference> <PropertyReference name="startTranscribe" type="void"> Emitted when audio transcription starts (the input switches to transcribe mode). </PropertyReference> <PropertyReference name="cancelTranscribe" type="void"> Emitted when audio transcription is cancelled (the input returns to input mode). </PropertyReference> <PropertyReference name="finishTranscribe" type="void"> Emitted when audio transcription finishes (the input returns to input mode). </PropertyReference> <PropertyReference name="finishTranscribeWithAudio" type="Blob"> Emitted with the recorded audio blob when transcription finishes with a recording. The blob is also handed to the surrounding `ChatState` for transcription. </PropertyReference> <PropertyReference name="addFile" type="void"> Emitted when the add-file action is triggered. Only active when attachments are enabled in the surrounding chat. </PropertyReference>For deep customization, provide named <ng-template> elements inside <copilot-chat-input>. Each is read with contentChild and takes precedence over the corresponding *Component input. The send button and toolbar templates receive a typed context.
import { Component, forwardRef, signal } from "@angular/core";
import { ChatState, CopilotChatInput } from "@copilotkit/angular";
import type { ToolsMenuItem } from "@copilotkit/angular";
@Component({
selector: "app-chat",
standalone: true,
imports: [CopilotChatInput],
providers: [
{
provide: ChatState,
useExisting: forwardRef(() => ChatComponent),
},
],
template: `
<copilot-chat-input [toolsMenu]="toolsMenu" />
`,
})
export class ChatComponent extends ChatState {
readonly inputValue = signal("");
toolsMenu: (ToolsMenuItem | "-")[] = [
{ label: "Summarize", action: () => this.summarize() },
"-",
{ label: "Translate", action: () => this.translate() },
];
summarize() {}
translate() {}
submitInput(value: string) {
// Send the message through your chat state owner.
}
changeInput(value: string) {
this.inputValue.set(value);
}
}