Skip to content
+

Chat - Scrolling

Auto-scroll behavior, scroll-to-bottom affordance, imperative scroll API, and history loading on scroll-up.

The message list automatically manages scroll position so that new messages and streaming content stay visible without user intervention, while still allowing the user to read earlier messages undisturbed.

Auto-scrolling

The message list automatically scrolls to the bottom when:

  • The user sends a new message (always active, regardless of configuration).
  • New messages arrive from the assistant while the user is near the bottom.
  • Streaming content grows (token-by-token updates).

The auto-scroll behavior is gated by a buffer — if the user has scrolled more than buffer pixels away from the bottom, automatic scrolling pauses so the user can read earlier messages without interruption.

Configuration

Control auto-scrolling through the features prop on ChatBox. The default buffer is 150 px.

{
  /* Custom 300 px buffer threshold */
}
<ChatBox adapter={adapter} features={{ autoScroll: { buffer: 300 } }} />;

{
  /* Disable auto-scroll entirely */
}
<ChatBox adapter={adapter} features={{ autoScroll: false }} />;

When auto-scroll is disabled, the user can still scroll to the bottom manually using the scroll-to-bottom affordance button.

MUI Assistant
Material UI chat
Styled with your active MUI theme
Material UI chat

Styled with your active MUI theme

MUI Assistant
MUI Assistant

Hello! I am styled using your active Material UI theme. Try sending a message.

You
You

Great — the bubble colors come from palette.primary and the typography from the theme.

Scroll-to-bottom affordance

A floating button appears when the user scrolls away from the bottom. Clicking it smoothly scrolls back to the latest message.

The affordance is enabled by default. Disable it with:

<ChatBox adapter={adapter} features={{ scrollToBottom: false }} />

The affordance also supports an unseen-message count badge and an aria-label that includes the unseen count when present.

Imperative scrolling

The ChatMessageList component exposes a ref handle for programmatic scroll control:

import { ChatMessageList } from '@mui/x-chat';
import type { MessageListRootHandle } from '@mui/x-chat/headless';

const listRef = React.useRef<MessageListRootHandle>(null);

// Scroll to bottom programmatically
listRef.current?.scrollToBottom({ behavior: 'smooth' });

<ChatMessageList ref={listRef} />;

MessageListContext

Child components inside the message list can access scroll state via context:

import { useMessageListContext } from '@mui/x-chat/headless';

function CustomScrollIndicator() {
  const { isAtBottom, unseenMessageCount, scrollToBottom } = useMessageListContext();

  if (isAtBottom) return null;
  return (
    <button onClick={() => scrollToBottom({ behavior: 'smooth' })}>
      {unseenMessageCount} new messages
    </button>
  );
}
Property Type Description
isAtBottom boolean Whether the scroll position is at the bottom
unseenMessageCount number Messages added since the user scrolled away
scrollToBottom (options?) => void Scroll to the latest message

History loading

When the user scrolls to the top of the message list, older messages are loaded automatically via the adapter's listMessages method. The message list preserves the current scroll position during prepend so the user doesn't lose their place.

The adapter signals whether more history is available through the hasMore flag:

async listMessages({ conversationId, cursor }) {
  const res = await fetch(`/api/conversations/${conversationId}/messages?cursor=${cursor ?? ''}`);
  const { messages, nextCursor, hasMore } = await res.json();
  return { messages, cursor: nextCursor, hasMore };
},

When hasMore is true, the message list continues to load older messages as the user scrolls up. When hasMore is false, scrolling to the top has no further effect.

You can also check the history loading state programmatically:

const { hasMoreHistory, loadMoreHistory } = useChat();

// Trigger manually if needed
await loadMoreHistory();

See also

  • Message list for the full component reference including date dividers, grouping, and density.
  • Streaming for how auto-scroll follows streaming content.
  • Adapter for the listMessages method that powers history loading.

API

See the documentation below for a complete reference to all of the props and classes available to the components mentioned here.