Message Scroller
A transcript that keeps the newest message in view, with a button back to it.
@cupertinoui/message-scrollerRegistry JSON "use client"
import * as React from "react"
import { Bubble, BubbleContent } from "@/components/ui/bubble"
import { Button } from "@/components/ui/button"
import { Message, MessageContent } from "@/components/ui/message"
import {
MessageScroller,
MessageScrollerButton,
MessageScrollerContent,
MessageScrollerItem,
MessageScrollerProvider,
MessageScrollerViewport,
} from "@/components/ui/message-scroller"
const replies = ["Sounds good!", "On my way.", "Can you share the file?", "Thanks!", "See you at 10."]
// A transcript that sticks to the newest message; scroll up and the button
// brings you back down.
export default function MessageScrollerDemo() {
const [messages, setMessages] = React.useState(() =>
Array.from({ length: 8 }, (_, index) => ({ id: String(index), mine: index % 2 === 1, text: replies[index % replies.length] }))
)
return (
<div className="flex w-full max-w-sm flex-col gap-3">
<MessageScrollerProvider>
<MessageScroller className="h-64 rounded-[14px] bg-mac-content shadow-[0_0_0_1px_var(--mac-grid)]">
<MessageScrollerViewport>
<MessageScrollerContent className="gap-2 p-3">
{messages.map((message) => (
<MessageScrollerItem key={message.id} messageId={message.id}>
<Message align={message.mine ? "end" : "start"}>
<MessageContent>
<Bubble variant={message.mine ? "default" : "secondary"}>
<BubbleContent>{message.text}</BubbleContent>
</Bubble>
</MessageContent>
</Message>
</MessageScrollerItem>
))}
</MessageScrollerContent>
</MessageScrollerViewport>
<MessageScrollerButton />
</MessageScroller>
</MessageScrollerProvider>
<Button
variant="secondary"
className="self-center"
onClick={() =>
setMessages((list) => [...list, { id: String(list.length), mine: list.length % 2 === 1, text: replies[list.length % replies.length] }])
}
>
Add Message
</Button>
</div>
)
}Installation
pnpm dlx shadcn@latest add @cupertinoui/message-scrollerThe first install also adds the macOS theme. See Installation to set up the registry.
Usage
import { MessageScroller, MessageScrollerContent, MessageScrollerItem, MessageScrollerProvider, MessageScrollerViewport } from "@/components/ui/message-scroller"
<MessageScrollerProvider>
<MessageScroller>
<MessageScrollerViewport>
<MessageScrollerContent>
<MessageScrollerItem messageId="1">…</MessageScrollerItem>
</MessageScrollerContent>
</MessageScrollerViewport>
</MessageScroller>
</MessageScrollerProvider>Built on @shadcn/react's headless Message Scroller.
API Reference
Every part forwards the props of the underlying element. The props below are the ones CupertinoUI adds or changes.
MessageScrollerProvider
| Prop | Type | Description |
|---|---|---|
autoScroll | booleanDefault: true | Follows new messages while at the end. |
className | string | Extra classes, merged with the component's own. |
MessageScrollerItem
| Prop | Type | Description |
|---|---|---|
messageId | string | Identifies the message, to scroll to it. |
className | string | Extra classes, merged with the component's own. |