Skip to content
+

Chat - Conversation header

Display the active conversation's title, subtitle, participants, and action buttons using the themed header components.

ChatConversationHeader is a <header> element with divider styling. It reads the active conversation through context so every child has access to the same conversation state without additional wiring.

Interactive playground

Configure the title, subtitle, and trailing actions of ChatConversationHeader—every header subcomponent (ChatConversationHeaderInfo, ChatConversationTitle, ChatConversationSubtitle, ChatConversationHeaderActions) is exercised in this single demo.

ChatConversationHeader
Top bar above the message list — title, subtitle, and action slot.

Styling questions

Theming MuiChatComposer

fixture (conversation data)
conversation.titlestring
Read by <ChatConversationTitle> from the active conversation.
conversation.subtitlestring
render <ChatConversationSubtitle>
composition
header action count2
Trailing icon button count.
import {
  ChatConversation,
  ChatConversationHeader,
  ChatConversationHeaderInfo,
  ChatConversationTitle,
  ChatConversationSubtitle,
  ChatConversationHeaderActions,
} from '@mui/x-chat';

Component anatomy

ChatConversation                    <- thread shell, derives the active conversation
  ChatConversationHeader            <- header bar with divider styling
    ChatConversationHeaderInfo      <- stacks title over subtitle
    ChatConversationTitle           <- conversation name
    ChatConversationSubtitle        <- secondary line (participants, presence, etc.)
    ChatConversationHeaderActions   <- action area (archive, mute, context menu)

The header sits at the top of the thread pane and provides the visual identity of the active conversation.

Setting the title and subtitle

ChatConversationTitle renders the active conversation's title. ChatConversationSubtitle renders its subtitle, which can include participant names, a presence indicator, or any descriptive text.

The ChatConversation type provides these fields:

interface ChatConversation {
  id: string;
  title?: string;
  subtitle?: string;
  avatarUrl?: string;
  participants?: ChatUser[];
  unreadCount?: number;
  readState?: ConversationReadState;
  lastMessageAt?: ChatDateTimeString;
  metadata?: ChatConversationMetadata;
}

How conversation state flows

ChatConversation provides the conversation state through React context. Each header subcomponent reads it from that context — no props need to be threaded through.

Conversation state fields

Field Type Description
conversationId string | undefined Currently selected conversation ID
conversation ChatConversation | null Full active conversation object, when loaded
hasConversation boolean Whether the thread currently has a selection

Use the hasConversation flag to hide action buttons or show a placeholder when no conversation is active. ChatConversationHeader, ChatConversationTitle, ChatConversationSubtitle, and ChatConversationHeaderActions all receive this same conversation-level state.

Customizing the action area

ChatConversationHeaderActions renders an action area on the right side of the header. Replace it to add archive, mute, or context menu buttons:

import IconButton from '@mui/material/IconButton';
import MoreVertIcon from '@mui/icons-material/MoreVert';
import ArchiveIcon from '@mui/icons-material/Archive';

const CustomActions = React.forwardRef(function CustomActions(
  { ownerState, ...props },
  ref,
) {
  if (!ownerState?.hasConversation) return null;

  return (
    <div ref={ref} {...props}>
      <IconButton size="small" aria-label="Archive conversation">
        <ArchiveIcon fontSize="small" />
      </IconButton>
      <IconButton size="small" aria-label="More options">
        <MoreVertIcon fontSize="small" />
      </IconButton>
    </div>
  );
});
Support thread

Replies in ~1h

Participants

The participants array on ChatConversation carries ChatUser objects with displayName, avatarUrl, and isOnline fields. Use these in a custom subtitle slot to show a participant list or online status:

const ParticipantSubtitle = React.forwardRef(function ParticipantSubtitle(
  { ownerState, ...props },
  ref,
) {
  const participants = ownerState?.conversation?.participants ?? [];
  const onlineCount = participants.filter((p) => p.isOnline).length;

  return (
    <span ref={ref} {...props}>
      {participants.length} participants ({onlineCount} online)
    </span>
  );
});

Attach it through the subtitle slot:

<ChatConversationSubtitle slots={{ subtitle: ParticipantSubtitle }} />

Slots and classes

Each header subcomponent exposes a single slot key for overriding its element, a CSS class for styling, and a corresponding ChatBox slot key:

Component Slot key CSS class ChatBox slot key
ChatConversationHeader header .MuiChatConversation-header conversationHeader
ChatConversationHeaderInfo headerInfo .MuiChatConversation-headerInfo conversationHeaderInfo
ChatConversationTitle title .MuiChatConversation-title conversationTitle
ChatConversationSubtitle subtitle .MuiChatConversation-subtitle conversationSubtitle
ChatConversationHeaderActions actions .MuiChatConversation-headerActions conversationHeaderActions

ChatConversationHeaderActions's slot key is actions even though its class is headerActions.

See the generated API pages for the full prop reference: ChatConversationHeader API, ChatConversationHeaderInfo API, ChatConversationTitle API, ChatConversationSubtitle API, and ChatConversationHeaderActions API.

Overriding a header slot

The most targeted customization is to replace the element type on one slot while keeping everything else:

import { ChatConversationHeader } from '@mui/x-chat';
import { styled } from '@mui/material/styles';

const GradientHeader = styled('header')(({ theme }) => ({
  background: `linear-gradient(135deg, ${theme.palette.primary.dark}, ${theme.palette.primary.main})`,
  color: theme.palette.primary.contrastText,
  '& *': { color: 'inherit' },
}));

function CustomHeader(props) {
  return <ChatConversationHeader {...props} slots={{ header: GradientHeader }} />;
}

Pass CustomHeader through ChatBox's slots.conversationHeader prop:

<ChatBox slots={{ conversationHeader: CustomHeader }} />
Design crit

Weekly sync

Press Enter to start editing

Customizing the title with conversation state

The ownerState prop received by slot components carries the full conversation context. Use it to render dynamic content derived from the active conversation. ownerState is injected by the component itself with the shape shown in Conversation state fields; passing your own ownerState prop to these components has no effect.

conversation.metadata is empty by default — augment ChatConversationMetadata with your app's fields (here, an illustrative memberCount). See Type augmentation.

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

const LiveTitle = React.forwardRef(function LiveTitle(
  { ownerState, children, ...props },
  ref,
) {
  const memberCount = ownerState?.conversation?.metadata?.memberCount;
  return (
    <div ref={ref} {...props}>
      {ownerState?.conversation?.title ?? 'No conversation selected'}
      {memberCount != null && (
        <span style={{ fontWeight: 400, marginLeft: 8 }}>{memberCount} members</span>
      )}
    </div>
  );
});

function CustomConversationTitle(props) {
  return <ChatConversationTitle {...props} slots={{ title: LiveTitle }} />;
}

The component passes the default content — conversation.title — to your slot as children; render it or replace it as shown.

Design crit4 members
Press Enter to start editing

Recomposing the header from scratch

When you need to insert additional content inside the header—for example, a typing indicator or a custom divider—assemble the header from individual Material UI components directly:

import {
  ChatConversation,
  ChatConversationHeader,
  ChatConversationHeaderInfo,
  ChatConversationTitle,
  ChatConversationSubtitle,
  ChatConversationHeaderActions,
} from '@mui/x-chat';
import Box from '@mui/material/Box';

function CustomThread() {
  return (
    <ChatConversation sx={{ height: '100%' }}>
      <ChatConversationHeader>
        <ChatConversationHeaderInfo>
          <ChatConversationTitle />
          <ChatConversationSubtitle />
        </ChatConversationHeaderInfo>
        <Box sx={{ flex: 1 }} />
        <ChatConversationHeaderActions />
      </ChatConversationHeader>
      {/* rest of the thread */}
    </ChatConversation>
  );
}

See also

  • Conversation list for the sidebar that lists conversations.
  • Real-time sync for live updates to conversation metadata displayed in the header.
  • Layout for the full thread anatomy including message list and composer.

API

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