<!-- Generated by scripts/gen-docs.mts from the JSDoc in registry/. Do not edit; run `pnpm run docs`. -->

# MessageList

A conversation: `Message`s in a scrolling, labeled region that opens at the newest one. While the reader is at the bottom it follows new messages and streaming text; once they scroll up, nothing moves their view, and a "Jump to latest" button appears. Each new message from someone else is read to screen readers once, politely: a streamed reply when it finishes, and a first reply in a list that mounted empty. History is never announced: the messages it mounts with, several messages filling an empty list at once (history fetched after mount), older messages loaded above, and a message whose `key` changes in place (a temporary id swapped for the server's). Older messages loaded above a scrolled-up reader leave the message they are reading where it was. Scrolling is never announced.

```tsx
import { MessageList } from "@/components/ouro/message/message-list";
```

## Example

```tsx
<MessageList label="Conversation with Ouro" className="h-[60dvh]">
  {messages.map((message) => (
    <Message key={message.id} role={message.role} name={message.author} streaming={message.streaming}>
      {message.text}
    </Message>
  ))}
</MessageList>
```

## Usage

Give it a height (`className="h-96"`, or `flex-1` in a column), since it scrolls inside it.

## Use instead when

- Use a plain list instead for messages that do not arrive live, such as an inbox.

## Props

Type: `MessageListProps`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children` (required) | `ReactNode` |  | The `Message`s, oldest first. |
| `className` | `string` |  | Layout only: the list's height (`h-96`, `flex-1`), margins. It scrolls inside that height, so give it one. Appearance classes warn in development. |
| `jumpLabel` | `string` | `"Jump to latest"` | The button that appears once the reader scrolls up, for other languages. |
| `label` (required) | `string` |  | What the conversation is, for screen readers: "Conversation with Ouro". Required, so the region has a name. |
| `newMessageLabel` | `((author: string, text: string) => string)` | (author, text) => `${author}: ${text}` | What screen readers hear when a new message arrives, for other languages. It gets the author's name and the message's text. The user's own messages are not read back. |
| `ref` | `Ref<HTMLDivElement>` |  | Reaches the rendered element. |

## Native attributes

Also accepts the attributes in React's `HTMLAttributes` (`id`, `aria-*`, event handlers), passed to the rendered element, except those named on this page.

## Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

- `autoScroll`: Not a prop. The list follows new messages while the reader is at the bottom, and stops when they scroll up.
- `stickToBottom`: Not a prop. The list follows new messages while the reader is at the bottom, and stops when they scroll up.

## `className` is for layout only

Pass margins, width and grid placement (`mt-4`, `w-full`, `col-span-2`). Your classes always win over Ouro UI's: MessageList merges `className` last with `cn` (tailwind-merge), so a class that conflicts with its own replaces it.[^layout-classes]

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (`hover:`, `sm:`) and any `!` are removed, it starts with `bg-`, `text-`, `border-`, `rounded-`, `shadow-`, `font-`, `ring-`, `from-`, `via-`, `to-`, `fill-` or `stroke-`, or is `border`, `rounded`, `shadow` or `ring`, or has a `dark:` variant. Text wrapping, overflow and table layout classes (`text-wrap`, `text-ellipsis`, `border-collapse`) are layout and do not warn.

Alignment classes (`text-center`) warn too: set alignment on a parent element.

[^layout-classes]: test:registry/ouro/components/ouro/message/message-list.test.tsx::MessageList > forwards a ref to the root and lets app layout classes win verify:testExists(registry/ouro/components/ouro/message/message-list.test.tsx::MessageList > forwards a ref to the root and lets app layout classes win)
