Chat UI and customization
Add a full Angular chat, choose its layout, and customize messages, slots, labels, and styles.
CopilotChat gives you a complete chat surface backed by the agent from your
Copilot Runtime. It owns message streaming, suggestions, the composer,
attachments, transcription, and the active thread.
This guide starts from the provider in the Angular quickstart and shows how to choose and customize the visible chat.
Choose a chat surface#
| Surface | Use it when |
|---|---|
CopilotChat | Chat belongs inside an existing page or panel. |
CopilotPopup | Chat should open from a floating launcher. |
CopilotSidebar | Chat should sit beside the main application or open as an overlay. |
CopilotChatView | You own the agent wiring and only need the chat layout. |
All four are standalone Angular components.
Add an inline chat#
Import CopilotChat, give its host a real height, and point it at an agent when
you do not want the default agent.
import { ChangeDetectionStrategy, Component } from "@angular/core";
import { CopilotChat } from "@copilotkit/angular";
@Component({
selector: "app-support-chat",
imports: [CopilotChat],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<section class="chat-shell" aria-label="Support assistant">
<copilot-chat agentId="support" />
</section>
`,
styles: `
.chat-shell {
height: min(48rem, 80vh);
overflow: hidden;
border: 1px solid #dbe3eb;
border-radius: 1rem;
}
`,
})
export class SupportChatComponent {}Import the package stylesheet once in the application's global stylesheet:
@import "@copilotkit/angular/styles.css";Use a popup or sidebar#
Both modal surfaces manage focus, Escape closing, and launcher-focus restore.
Their open model supports two-way binding.
import { Component, signal } from "@angular/core";
import { CopilotPopup, CopilotSidebar } from "@copilotkit/angular";
@Component({
selector: "app-root",
imports: [CopilotPopup, CopilotSidebar],
template: `
<copilot-popup
[(open)]="popupOpen"
title="Support assistant"
[clickOutsideToClose]="true"
/>
<copilot-sidebar
[(open)]="sidebarOpen"
mode="docked"
position="right"
title="Workspace assistant"
[width]="480"
/>
`,
})
export class AppComponent {
readonly popupOpen = signal(false);
readonly sidebarOpen = signal(false);
}Compact viewports render the sidebar as a modal even when mode is "docked".
Only one open docked sidebar can own the page margin at a time.
Replace an assistant message#
Pass a standalone component class to assistantMessageComponent. CopilotKit
creates it for each assistant message and binds its message input.
import { ChangeDetectionStrategy, Component, input } from "@angular/core";
type AssistantMessage = {
id: string;
role: "assistant";
content?: string;
};
@Component({
selector: "app-custom-assistant-message",
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<article class="answer">
<span class="answer__label">Assistant</span>
<p>{{ message().content }}</p>
</article>
`,
})
export class CustomAssistantMessageComponent {
readonly message = input.required<AssistantMessage>();
}import { Component } from "@angular/core";
import { CopilotChat } from "@copilotkit/angular";
import { CustomAssistantMessageComponent } from "./custom-assistant-message.component";
@Component({
selector: "app-support-chat",
imports: [CopilotChat],
template: `
<copilot-chat
[assistantMessageComponent]="assistantMessageComponent"
assistantMessageClass="support-answer"
/>
`,
})
export class SupportChatComponent {
protected readonly assistantMessageComponent =
CustomAssistantMessageComponent;
}CopilotChat also accepts component or template slots for reasoning messages,
the composer, and content after the transcript. Use CopilotChatView directly
when you need its scroll view, disclaimer, feather, input-container, or
scroll-to-bottom slots.
Scope CSS changes#
The package stylesheet exposes stable chat classes. Put a scope class on your feature host so the change stays local.
.support-chat .copilotKitUserMessage {
color: white;
background: #2563eb;
border-radius: 0.75rem;
}
.support-chat .copilotKitAssistantMessage {
padding: 0.75rem;
color: #172554;
background: #eff6ff;
border-radius: 0.75rem;
}