Skip to content
+

Chat - Headless indicators

Use shared structural affordances for typing, unread boundaries, and scroll-to-bottom behavior.

Indicator thread
Typing, unread boundaries, and scroll state
Alice Chen
Alice Chen
Confirmed the unread marker still lands at the right boundary. Item 23.
You
You
Added one more note so the scroll affordance becomes visible while scrolled away. Item 24.
Sent
MUI Guide
MUI Guide
Reviewed the latest support transcript and normalized the key states. Item 25.
You
You
Queued the oldest messages for prepend pagination. Item 26.
Sent
Alice Chen
Alice Chen
Confirmed the unread marker still lands at the right boundary. Item 27.
You
You
Added one more note so the scroll affordance becomes visible while scrolled away. Item 28.
Sent
MUI Guide
MUI Guide
Reviewed the latest support transcript and normalized the key states. Item 29.
You
You
Queued the oldest messages for prepend pagination. Item 30.
Sent
Alice Chen
Alice Chen
Confirmed the unread marker still lands at the right boundary. Item 31.
You
You
Added one more note so the scroll affordance becomes visible while scrolled away. Item 32.
Sent
MUI Guide
MUI Guide
Reviewed the latest support transcript and normalized the key states. Item 33.
New messages
You
You
Queued the oldest messages for prepend pagination. Item 34.
Sent
Alice Chen
Alice Chen
Confirmed the unread marker still lands at the right boundary. Item 35.
You
You
Added one more note so the scroll affordance becomes visible while scrolled away. Item 36.
Sent

Primitive set

The indicator group is built from:

  • Indicators.TypingIndicator
  • Indicators.UnreadMarker
  • Indicators.ScrollToBottomAffordance

These primitives are small, but they encode thread-specific semantics that are easy to get wrong when rebuilt from scratch.

TypingIndicator

TypingIndicator reads typing state for the active conversation and resolves display names from:

  • conversation participants
  • message authors already present in the thread
  • raw user ids when no richer user data is available

It renders a polite live region and shows labels such as:

  • Alice is typing
  • Alice, Bob are typing

Typical placement

import { Indicators, Conversation } from '@mui/x-chat/headless';

<Conversation.Header>
  <Conversation.Title />
  <Conversation.Subtitle />
  <Indicators.TypingIndicator />
</Conversation.Header>;

Use it in the thread header or just above the composer when typing feedback should stay close to the active draft area.

UnreadMarker

UnreadMarker inserts a structural boundary into the message flow.

The unread boundary is derived from the active conversation state:

  • conversation.unreadCount
  • conversation.readState

The component renders only for the row that starts the unread region and applies role="separator" so the boundary stays meaningful to assistive technology.

Typical placement

<MessageList.Root
  renderItem={({ id, index }) => (
    <React.Fragment>
      <Indicators.UnreadMarker index={index} messageId={id} />
      <MessageGroup index={index} messageId={id} />
    </React.Fragment>
  )}
/>

You can replace both the separator root and the label through slots.

ScrollToBottomAffordance

ScrollToBottomAffordance consumes message-list context and appears only when the user is away from the bottom of the thread.

It supports:

  • scroll-to-bottom action wiring
  • unseen-message count badges
  • an aria-label that includes the unseen count when present

The primitive expects to live inside the MessageList.Root context, usually in a custom message-list root slot or another descendant of the list surface.

Typical placement

function MessageListShell(props) {
  return (
    <div {...props}>
      {props.children}
      <Indicators.ScrollToBottomAffordance />
    </div>
  );
}

When the user is already at the bottom of the thread, the affordance returns null.

Slots and owner state

The indicator primitives expose the following slot surfaces:

  • TypingIndicator: root
  • UnreadMarker: root, label
  • ScrollToBottomAffordance: root, badge

Custom slots receive owner state such as:

  • resolved typing users and count
  • unread-boundary presence and label
  • unseen-message count and isAtBottom

That makes it straightforward to map the indicators into an existing design system without rewriting the underlying behavior.

See also

  • Continue with Message list for the list context that powers unread boundaries and scroll affordances.
  • Continue with Thread for header composition patterns.
  • Continue with Indicators in context for the demo version of these primitives.

API

API

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