Skip to main content

Overview

CopilotKit provides pre-built Angular components for chat interfaces. These components are standalone, support signals for reactivity, and offer extensive customization through slots and templates.

CopilotChatMessageView

Renders a list of messages with support for assistant and user messages, custom layouts, and tool call rendering.

Usage

import { Component } from '@angular/core';
import { CopilotChatMessageView } from '@copilotkit/angular';

@Component({
  selector: 'app-chat',
  standalone: true,
  imports: [CopilotChatMessageView],
  template: `
    <copilot-chat-message-view
      [messages]="messages"
      [isLoading]="isLoading"
      [showCursor]="showCursor"
    />
  `
})
export class ChatComponent {
  messages = signal<Message[]>([]);
  isLoading = signal(false);
  showCursor = signal(true);
}

Inputs

messages
Message[]
default:"[]"
Array of messages to display. Messages should have a role of 'user', 'assistant', or 'tool'.
showCursor
boolean
default:"false"
Whether to show a blinking cursor at the end of the message list (typically while loading).
isLoading
boolean
default:"false"
Whether the agent is currently processing a response.
inputClass
string
CSS classes to apply to the container element.
assistantMessageComponent
Type<any>
Custom component to render assistant messages.
assistantMessageTemplate
TemplateRef<any>
Custom template to render assistant messages.
assistantMessageClass
string
CSS classes to apply to assistant messages.
userMessageComponent
Type<any>
Custom component to render user messages.
userMessageTemplate
TemplateRef<any>
Custom template to render user messages.
userMessageClass
string
CSS classes to apply to user messages.
cursorComponent
Type<any>
Custom component for the cursor.
cursorTemplate
TemplateRef<any>
Custom template for the cursor.
cursorClass
string
CSS classes to apply to the cursor.

Outputs

assistantMessageThumbsUp
EventEmitter<{ message: Message }>
Emitted when user clicks thumbs up on an assistant message.
assistantMessageThumbsDown
EventEmitter<{ message: Message }>
Emitted when user clicks thumbs down on an assistant message.
assistantMessageReadAloud
EventEmitter<{ message: Message }>
Emitted when user clicks read aloud on an assistant message.
assistantMessageRegenerate
EventEmitter<{ message: Message }>
Emitted when user requests message regeneration.
userMessageCopy
EventEmitter<{ message: Message }>
Emitted when user copies a user message.
userMessageEdit
EventEmitter<{ message: Message }>
Emitted when user edits a user message.

Examples

Basic Message View

import { Component, signal } from '@angular/core';
import { CopilotChatMessageView } from '@copilotkit/angular';
import type { Message } from '@ag-ui/core';

@Component({
  selector: 'app-chat',
  standalone: true,
  imports: [CopilotChatMessageView],
  template: `
    <copilot-chat-message-view
      [messages]="messages()"
      [isLoading]="isLoading()"
      [showCursor]="isLoading()"
      (assistantMessageThumbsUp)="handleThumbsUp($event)"
      (assistantMessageThumbsDown)="handleThumbsDown($event)"
    />
  `
})
export class ChatComponent {
  messages = signal<Message[]>([
    { id: '1', role: 'user', content: 'Hello!' },
    { id: '2', role: 'assistant', content: 'Hi! How can I help you?' }
  ]);
  isLoading = signal(false);
  
  handleThumbsUp(event: { message: Message }) {
    console.log('Thumbs up:', event.message);
  }
  
  handleThumbsDown(event: { message: Message }) {
    console.log('Thumbs down:', event.message);
  }
}

Custom Layout Template

@Component({
  selector: 'app-chat',
  standalone: true,
  imports: [CopilotChatMessageView],
  template: `
    <copilot-chat-message-view [messages]="messages()">
      <ng-template #customLayout let-messages="messages" let-isLoading="isLoading">
        <div class="custom-layout">
          <h2>Chat Messages</h2>
          @for (message of messages; track message.id) {
            <div class="message-{{ message.role }}">
              {{ message.content }}
            </div>
          }
          @if (isLoading) {
            <div class="loading">Loading...</div>
          }
        </div>
      </ng-template>
    </copilot-chat-message-view>
  `
})
export class ChatComponent {
  messages = signal<Message[]>([]);
}

Custom Message Components

// custom-assistant-message.component.ts
@Component({
  selector: 'app-custom-assistant-message',
  standalone: true,
  template: `
    <div class="custom-assistant">
      <strong>AI:</strong> {{ message.content }}
    </div>
  `
})
export class CustomAssistantMessageComponent {
  @Input() message!: Message;
}

// chat.component.ts
@Component({
  selector: 'app-chat',
  standalone: true,
  imports: [CopilotChatMessageView],
  template: `
    <copilot-chat-message-view
      [messages]="messages()"
      [assistantMessageComponent]="customAssistantComponent"
    />
  `
})
export class ChatComponent {
  messages = signal<Message[]>([]);
  customAssistantComponent = CustomAssistantMessageComponent;
}

CopilotChatInput

An input component for sending messages, with support for voice transcription, file uploads, and tool menus.

Usage

import { Component, signal } from '@angular/core';
import { CopilotChatInput } from '@copilotkit/angular';

@Component({
  selector: 'app-chat',
  standalone: true,
  imports: [CopilotChatInput],
  template: `
    <copilot-chat-input
      [value]="inputValue()"
      (submitMessage)="handleSubmit($event)"
      (valueChange)="inputValue.set($event)"
    />
  `
})
export class ChatComponent {
  inputValue = signal('');
  
  handleSubmit(message: string) {
    console.log('Submitted:', message);
    this.inputValue.set('');
  }
}

Inputs

value
string
Current value of the input field.
mode
'input' | 'transcribe' | 'processing'
Current input mode. Controls the UI state.
autoFocus
boolean
default:"true"
Whether to auto-focus the input on mount.
inputClass
string
CSS classes to apply to the wrapper element.
toolsMenu
(ToolsMenuItem | '-')[]
Array of tool menu items to display. Use '-' for separators.
additionalToolbarItems
TemplateRef<any>
Template for additional toolbar items.
sendButtonClass
string
CSS classes for the send button.
sendButtonComponent
Type<any>
Custom component for the send button.
textAreaClass
string
CSS classes for the textarea.
textAreaComponent
Type<any>
Custom component for the textarea.
textAreaMaxRows
number
Maximum number of rows for the auto-expanding textarea.
textAreaPlaceholder
string
Placeholder text for the textarea.
toolbarClass
string
CSS classes for the toolbar.
toolbarComponent
Type<any>
Custom component for the toolbar.
audioRecorderClass
string
CSS classes for the audio recorder.
audioRecorderComponent
Type<any>
Custom component for the audio recorder.

Outputs

submitMessage
EventEmitter<string>
Emitted when user submits a message (Enter key or send button).
valueChange
EventEmitter<string>
Emitted when the input value changes.
startTranscribe
EventEmitter<void>
Emitted when voice transcription starts.
cancelTranscribe
EventEmitter<void>
Emitted when voice transcription is cancelled.
finishTranscribe
EventEmitter<void>
Emitted when voice transcription finishes.
addFile
EventEmitter<void>
Emitted when the add file button is clicked.

Examples

Basic Input

import { Component, signal } from '@angular/core';
import { CopilotChatInput } from '@copilotkit/angular';

@Component({
  selector: 'app-chat-input',
  standalone: true,
  imports: [CopilotChatInput],
  template: `
    <copilot-chat-input
      [value]="value()"
      [textAreaPlaceholder]="'Ask me anything...'"
      (submitMessage)="onSubmit($event)"
      (valueChange)="value.set($event)"
    />
  `
})
export class ChatInputComponent {
  value = signal('');
  
  onSubmit(message: string) {
    console.log('Message:', message);
    // Send to agent
  }
}

With Voice Transcription

@Component({
  selector: 'app-chat-input',
  standalone: true,
  imports: [CopilotChatInput],
  template: `
    <copilot-chat-input
      [value]="value()"
      [mode]="mode()"
      (submitMessage)="onSubmit($event)"
      (startTranscribe)="mode.set('transcribe')"
      (cancelTranscribe)="mode.set('input')"
      (finishTranscribe)="onFinishTranscribe()"
    />
  `
})
export class ChatInputComponent {
  value = signal('');
  mode = signal<'input' | 'transcribe' | 'processing'>('input');
  
  onSubmit(message: string) {
    this.mode.set('processing');
    // Send to agent
  }
  
  onFinishTranscribe() {
    this.mode.set('input');
    // Transcribed text is automatically set to value
  }
}

With Tools Menu

import type { ToolsMenuItem } from '@copilotkit/angular';

@Component({
  selector: 'app-chat-input',
  standalone: true,
  imports: [CopilotChatInput],
  template: `
    <copilot-chat-input
      [toolsMenu]="toolsMenu"
      (submitMessage)="onSubmit($event)"
    />
  `
})
export class ChatInputComponent {
  toolsMenu: ToolsMenuItem[] = [
    {
      name: 'Search Database',
      icon: '🔍',
      onClick: () => this.triggerSearch()
    },
    '-', // Separator
    {
      name: 'Export Data',
      icon: '📥',
      onClick: () => this.exportData()
    }
  ];
  
  onSubmit(message: string) {
    // Handle message
  }
  
  triggerSearch() {
    console.log('Triggering search...');
  }
  
  exportData() {
    console.log('Exporting data...');
  }
}

Custom Send Button

// custom-send-button.component.ts
@Component({
  selector: 'app-custom-send-button',
  standalone: true,
  template: `
    <button
      [disabled]="disabled"
      (click)="send()"
      class="custom-send-btn"
    >
      Send Message
    </button>
  `
})
export class CustomSendButtonComponent {
  @Input() send!: () => void;
  @Input() disabled!: boolean;
  @Input() value!: string;
}

// chat.component.ts
@Component({
  selector: 'app-chat',
  standalone: true,
  imports: [CopilotChatInput],
  template: `
    <copilot-chat-input
      [sendButtonComponent]="customSendButton"
      (submitMessage)="onSubmit($event)"
    />
  `
})
export class ChatComponent {
  customSendButton = CustomSendButtonComponent;
  
  onSubmit(message: string) {
    console.log('Submitted:', message);
  }
}

Additional Toolbar Items

@Component({
  selector: 'app-chat-input',
  standalone: true,
  imports: [CopilotChatInput],
  template: `
    <copilot-chat-input (submitMessage)="onSubmit($event)">
      <ng-template #additionalItems>
        <button (click)="clearHistory()">Clear</button>
        <button (click)="exportChat()">Export</button>
      </ng-template>
    </copilot-chat-input>
  `
})
export class ChatInputComponent {
  onSubmit(message: string) {
    // Handle submit
  }
  
  clearHistory() {
    console.log('Clearing history...');
  }
  
  exportChat() {
    console.log('Exporting chat...');
  }
}

Styling

All components support Tailwind CSS classes and can be fully customized:
<copilot-chat-message-view
  [inputClass]="'bg-gray-100 p-4 rounded-lg'"
  [assistantMessageClass]="'bg-blue-50 border-blue-200'"
  [userMessageClass]="'bg-green-50 border-green-200'"
/>

<copilot-chat-input
  [inputClass]="'shadow-xl'"
  [sendButtonClass]="'bg-primary text-white'"
  [textAreaClass]="'min-h-[100px]'"
/>

See Also