Platform Foundationsv0.2.0

Message Scroller

A scrollable message container with auto-scroll and jump-to-end button.

U
Hey, can you check the new chart component?
Already reviewed it — the Recharts integration looks solid.
U
Great. Did the data-table typecheck pass?
Yes, TanStack Table is wired up and working.
U
Let's ship it then.

When to use

MessageScroller is for a live transcript: it holds the newest message in view while output streams in and reveals a jump-to-latest button once the user scrolls away. A bounded static list is a ScrollArea instead, and the turns inside the transcript are still Message and Bubble.

Platform notes

It needs the full nesting (Provider, Root, Viewport, Content, Item) inside a parent with a resolved height, h-80 in the demo, or autoscroll has nothing to measure and the button never activates. Unlike the rest of the catalog it pulls a runtime dependency, @shadcn/react, which is not in the ARCHITECTURE.md stack table, so record the deviation in the app before adopting it. MessageScrollerItem sets content-visibility: auto with an intrinsic size hint, so give images and embeds explicit dimensions or the transcript jumps as items render. The jump button ships a hardcoded English sr-only label that has to become an i18next message, and the viewport asks for a scroll-fade-b utility the theme does not define, so do not rely on that fade to signal more content.

Install

npx shadcn@latest add message-scroller

Code

"use client";

import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Bubble, BubbleContent } from "@/components/ui/bubble";
import { Message, MessageAvatar, MessageContent, MessageGroup } from "@/components/ui/message";
import {
  MessageScroller,
  MessageScrollerButton,
  MessageScrollerContent,
  MessageScrollerItem,
  MessageScrollerProvider,
  MessageScrollerViewport,
} from "@/components/ui/message-scroller";
import { Bot } from "lucide-react";

const messages = [
  { id: 1, text: "Hey, can you check the new chart component?", sender: "user" },
  { id: 2, text: "Already reviewed it — the Recharts integration looks solid.", sender: "bot" },
  { id: 3, text: "Great. Did the data-table typecheck pass?", sender: "user" },
  { id: 4, text: "Yes, TanStack Table is wired up and working.", sender: "bot" },
  { id: 5, text: "Let's ship it then.", sender: "user" },
];

export function MessageScrollerDemo() {
  return (
    <div className="h-80 w-full max-w-md rounded-lg border">
      <MessageScrollerProvider>
        <MessageScroller>
          <MessageScrollerViewport>
            <MessageScrollerContent>
              {messages.map((msg) => (
                <MessageScrollerItem key={msg.id}>
                  <MessageGroup>
                    <Message align={msg.sender === "user" ? "end" : "start"}>
                      <MessageAvatar>
                        <Avatar>
                          <AvatarFallback>{msg.sender === "user" ? "U" : <Bot />}</AvatarFallback>
                        </Avatar>
                      </MessageAvatar>
                      <MessageContent>
                        <Bubble
                          variant={msg.sender === "user" ? "default" : "tinted"}
                          align={msg.sender === "user" ? "end" : "start"}
                        >
                          <BubbleContent>{msg.text}</BubbleContent>
                        </Bubble>
                      </MessageContent>
                    </Message>
                  </MessageGroup>
                </MessageScrollerItem>
              ))}
            </MessageScrollerContent>
          </MessageScrollerViewport>
          <MessageScrollerButton />
        </MessageScroller>
      </MessageScrollerProvider>
    </div>
  );
}

Full API

ui.shadcn.com/docs/components/message-scroller