Chat Container
A scroll area that auto-sticks to the bottom on new content — but only if the user is already there. For a back-to-bottom affordance, bind a spartan hlmBtn to the container's canScrollDown() and scrollToBottom(); pinToTop() holds a just-sent message at the top while the reply comes in.
Examples
Auto-scroll on new messages
Add a message; the container scrolls to keep up. Scroll up manually and the auto-scroll yields to you — the floating button takes you back.
<pk-chat-container-root #thread class="relative h-[360px] p-4">
<pk-chat-container-content class="gap-3">
@for (m of messages(); track m.id) {
<div hlmMessage>
<div hlmMessageAvatar>
<hlm-avatar>
<img hlmAvatarImage [src]="m.avatar" alt="" />
<span hlmAvatarFallback>AI</span>
</hlm-avatar>
</div>
<div hlmMessageContent>
<div hlmBubble variant="secondary">
<div hlmBubbleContent>{{ m.text }}</div>
</div>
</div>
</div>
}
</pk-chat-container-content>
<pk-chat-container-scroll-anchor />
<div class="sticky bottom-2 ml-auto w-fit pr-1">
<button
hlmBtn
variant="outline"
size="icon"
type="button"
aria-label="Scroll to bottom"
class="size-10 rounded-full transition-all duration-150 ease-out data-[hidden=true]:pointer-events-none data-[hidden=true]:translate-y-4 data-[hidden=true]:scale-95 data-[hidden=true]:opacity-0"
[attr.data-hidden]="thread.isAtBottom()"
(click)="thread.scrollToBottom()"
>
<ng-icon name="lucideChevronDown" />
</button>
</div>
</pk-chat-container-root>Installation
Add the chat-container component (and the cn() utility) to your project.
ng generate ngx-prompt-kit:chat-containerComponent API
PkChatContainerRoot
| Prop | Type | Default | Description |
|---|---|---|---|
| class | string | — | Extra classes for the scroll container. |
| isAtBottom | Signal<boolean> | — | Read-only signal exposed via CHAT_CONTAINER_STATE. |
| scrollToBottom() | (behavior?: ScrollBehavior) => void | — | Method to programmatically scroll to bottom. Ends a pin. |
| canScrollDown | Signal<boolean> | — | Whether there is content below the view (the room kept under a pinned turn not counted). Bind a spartan hlmBtn to it for a back-to-bottom button. |
| pinToTop() | (element: HTMLElement, offset?: number) => void | — | Scrolls a turn to the top of the view, offset px below the edge (16 by default), and holds it there while the reply below grows, keeping room under it as long as the reply is shorter than the view. Call it with a message the user just sent, as Claude does. |
PkChatContainerContent
| Prop | Type | Default | Description |
|---|---|---|---|
| class | string | — | Extra classes for the inner flex column. |
PkChatContainerScrollAnchor
| Prop | Type | Default | Description |
|---|---|---|---|
| class | string | — | Extra classes for the 1-pixel anchor element. |