# MessageList
A conversation that stays pinned to the newest message unless the reader scrolls up.
```ehtml Example
import { MessageList, MessageListEmpty, MessageListDownload } from "@elements/ui/message-list";
import { Message, MessageContent, MessageResponse } from "@elements/ui/message";
m.id} from={m.role}>
```
## Parts
| Part | What it is |
|---|---|
| `MessageList` | The scroller. Fills its container's height and follows new content while at the bottom. |
| `.message-list-viewport` | role=log, focusable so the keyboard can scroll it. |
| `.message-list-content` | The messages, spaced by --message-list-gap; grouped follow-ups sit closer. |
| `.message-list-scroll` | Scroll to latest: shown when not at the bottom, floating over the messages. |
| `MessageListEmpty` | A centered placeholder for an empty conversation. |
| `MessageListDownload` | Saves the conversation as a Markdown file. |
| `messagesToMarkdown()` | The Markdown the download writes; takes an optional formatter. |
## Attributes
### MessageList
| Attribute | Type | Default | Description |
|---|---|---|---|
| `label` | `string` | `"Conversation"` | The log's accessible name. |
| `stickToBottom` | `boolean` | `true` | Follow new content while at the bottom. |
| `initial` | `"smooth" \| "instant" \| "none" \| { damping, stiffness, mass }` | `"smooth"` | How it reaches the newest message on mount. |
| `resize` | `"smooth" \| "instant" \| { damping, stiffness, mass }` | `"smooth"` | How it follows growing content: native smooth, instant, or a spring (defaults 0.7, 0.05, 1.25). Reduced motion makes every mode instant. |
| `contentClass` | `string` | `""` | Extra classes on the content wrapper. |
| `contentAttrs` | `Record` | `{}` | Attributes spread on the content wrapper. |
| `threshold` | `number` | `70` | Pixels from the end that still count as at the bottom. |
| `targetScrollTop` | `((target, { scrollElement, contentElement }) => number) \| null` | `null` | Moves the bottom the list follows, such as the top of the newest reply; clamped to the scroll range. |
| `atBottom` | `boolean` (two-way) | `true` | False once the reader scrolls up. Set it true to scroll down and follow again. |
| `busy` | `boolean` | `false` | aria-busy on the log while a reply streams, so it is announced once, finished. |
| `scrollButton` | `boolean` | `true` | Render the scroll to latest button. |
| `scrollButtonLabel` | `string` | `"Scroll to latest"` | Its accessible name. |
| `scrollButtonVariant` | `"primary" \| "secondary" \| "outline" \| "ghost" \| "link" \| "danger"` | `"outline"` | The scroll button's variant. |
| `scrollButtonClass` | `string` | `""` | Appended to the scroll button's class. |
| `scrollButtonAttrs` | `Record` | `{}` | Attributes spread on the scroll button. |
| `onAtBottomChange` | `(atBottom: boolean) => void` | `() => {}` | Fires when the reader leaves or reaches the bottom. |
| `class` | `string` | `""` | Extra classes on the root. |
| `attrs` | `Record` | `{}` | Other attributes for the root. |
### MessageListEmpty
| Attribute | Type | Default | Description |
|---|---|---|---|
| `title` | `string` | `"No messages yet"` | Heading. |
| `description` | `string` | `"Start a conversation to see messages here"` | Text under it. |
### MessageListDownload
| Attribute | Type | Default | Description |
|---|---|---|---|
| `messages` | `ChatMessageLike[]` | (required) | { role, text?, content?, parts? }. Messages from common AI chat toolkits, with text in parts, work as they are. |
| `filename` | `string` | `"conversation.md"` | The saved file's name. |
| `formatMessage` | `(message, index) => string` | `**Role:** text` | Formats each message. |
| `label` | `string` | `"Download conversation"` | Accessible name and tooltip. |
## Slots
| Slot | Part | Content |
|---|---|---|
| `default` | `MessageList` | Messages, or a MessageListEmpty. |
| `overlay` | `MessageList` | Floating controls at the top inline end, such as MessageListDownload. |
| `scroll-icon` | `MessageList` | Replaces the scroll button's arrow icon. |
| `icon` | `MessageListEmpty` | An icon above the title. |
| `default` | `MessageListEmpty` | Extra content under the text, such as suggestions. |
| `default` | `MessageListDownload` | A custom icon. |
## Keyboard
| Keys | Action |
|---|---|
| `Tab` | Focuses the log, a scrollable region. |
| `ArrowUp / ArrowDown` | Scroll the focused log. Scrolling up stops following new messages. |
| `PageUp / PageDown` | Scroll by a page. |
| `Home / End` | Jump to the oldest or newest message. End follows again. |
| `Enter / Space` | On the scroll button: back to the newest message, following again; focus moves to the log as the button hides. |
## Data attributes
| Attribute | Values | On |
|---|---|---|
| `data-at-bottom` | present at the bottom | .message-list |
| `data-stuck` | present while following new content | .message-list |
## Accessibility
- The viewport is role=log (a polite live region) with an aria-label, so each new message is announced.
- busy sets aria-busy while a reply streams; screen readers read the finished text instead of every token.
- The viewport is focusable, so keyboard users can scroll the conversation.
- The scroll button is named Scroll to latest and leaves the tab order while hidden.
## See also
- [Message](message): One chat message with avatar, author, time, streaming Markdown, attachments, actions and response branches.
- [PromptInput](prompt-input): A growing message composer with attachments, tools, a model picker and a send button that stops a streaming reply.
- [Attachment](attachment): A file or source as a thumbnail, chip or row, with preview, size, upload progress and remove.