Chat · Components

ChatPopupComponent

ChatPopupComponent is a composition that renders a floating launcher button in the bottom-right corner of the screen. Clicking the launcher opens a chat window as an overlay. The window can be toggled open and closed without destroying conversation state.

Selector: chat-popup

Import:

import { ChatPopupComponent } from '@threadplane/chat';

#When to Use It

Use ChatPopupComponent when you want an unobtrusive chat entry point that does not occupy permanent screen real estate. The popup stays out of the way until the user chooses to engage, making it ideal for support chat, contextual help, and assistant features embedded in existing applications.

If you need the chat to always be visible, use <chat> (embedded) instead. If you need a slide-in panel alongside your app content, use <chat-sidebar>.

#Basic Usage

import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { injectAgent, provideAgent } from '@threadplane/langgraph';
import { ChatPopupComponent } from '@threadplane/chat';
 
@Component({
  selector: 'app-root',
  standalone: true,
  imports: [ChatPopupComponent],
  providers: [provideAgent({ apiUrl: 'http://localhost:2024', assistantId: 'chat', threadId: signal(null) })],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <!-- your app content here -->
    <chat-popup [agent]="chatAgent" />
  `,
})
export class AppComponent {
  protected readonly chatAgent = injectAgent();
}
Place at the root level

ChatPopupComponent uses position: fixed internally. Place it as a direct child of your root component or app shell so it is not clipped by a parent with overflow: hidden.

#API

#Inputs

InputTypeDefaultDescription
agentAgentRequiredThe agent providing streaming state
viewsViewRegistry | undefinedundefinedA2UI/json-render component registry forwarded to the inner <chat>
clientToolsClientToolRegistry | undefinedundefinedFrontend-declared client tools forwarded to the inner <chat>
modelOptionsreadonly ChatSelectOption[][]Options for the chat input model picker
showModelPickerbooleantrueHides the model picker when false, even when modelOptions is non-empty
selectedModelstring (two-way)''Current selected model value
openboolean (two-way)falseTwo-way bindable. Controls whether the chat window is open
shortcutstring | null'k'Single key toggled with Cmd/Ctrl. Set to null to disable
closeOnEscapebooleantrueCloses the popup when Escape is pressed

#Outputs

OutputTypeDescription
openChangebooleanEmits when the window opens or closes. Use with [(open)] for two-way binding

#Slots

SlotSelectorDescription
Header content[chatHeader]Projected into the chat window header bar. Replaces the default title

#Methods

MethodDescription
toggle()Toggles the window between open and closed
openWindow()Opens the chat window
closeWindow()Closes the chat window

#Two-Way Binding

Control the open state from your component:

@Component({
  template: `
    <button (click)="popup.openWindow()">Open Chat</button>
    <chat-popup [(open)]="chatOpen" [agent]="chatAgent" #popup />
  `,
  providers: [provideAgent({ apiUrl: 'http://localhost:2024', assistantId: 'chat', threadId: signal(null) })],
})
export class AppComponent {
  chatOpen = false;
  chatAgent = injectAgent();
}

#Custom Header

Project content into the window header with the [chatHeader] slot:

<chat-popup [agent]="chatAgent">
  <span chatHeader>Support Chat</span>
</chat-popup>

#A2UI and Client Tools

ChatPopupComponent forwards views and clientTools to the inner <chat> composition. Pass the same registries you would pass to <chat> when the popup needs generative UI surfaces or browser-executed tools:

<chat-popup
  [agent]="chatAgent"
  [views]="a2uiViews"
  [clientTools]="clientTools"
/>

#Styling

The popup uses the standard --tplane-chat-* token system. To adjust the launcher position:

chat-popup {
  --tplane-chat-launcher-offset-x: 1.5rem;
  --tplane-chat-launcher-offset-y: 1.5rem;
}

See Theming for the full token reference.