ComponentContext

ComponentContext holds the override keys: for each replaceable part of the UI, the component to render instead of the SDK's. Set keys with WithComponents, and read them with useComponentContext(). Overriding components explains how overrides apply and lists the keys by area of the screen. This page lists what each key's component receives and what renders by default.

Best practices

  • Declare the overrides object once, at module scope or with useMemo. A new object on every render re-renders every component that reads the context, each message included.
  • Put WithComponents above the component that reads the key. Chat reads NotificationAnnouncer, so that key only works from a WithComponents around Chat.
  • Use WithComponents, which merges with the overrides above it. ComponentProvider replaces them all, so use it only to reset a subtree to the defaults.
  • A custom MessageUI or VirtualMessage receives no props. It reads the message with useMessageContext(). See A custom MessageUI.
  • Before rebuilding a part, check whether the default takes what you need. For example, to change the message actions, render MessageActions with your own messageActionSet, as Message actions shows.

Basic usage

The SDK reads a key and falls back to its own component. A component of yours can do the same, so it shows whatever the app registered:

import {
  LoadingIndicator as DefaultLoadingIndicator,
  useComponentContext,
} from "stream-chat-react";

export const MembersLoading = () => {
  const { LoadingIndicator = DefaultLoadingIndicator } = useComponentContext();

  return <LoadingIndicator />;
};

useComponentContext() returns {} outside every provider. It never throws.

Registering overrides with WithComponents

WithComponents merges its overrides into the context from above. A nested one adds its keys and keeps the rest:

import type {
  Channel as StreamChannel,
  Thread as StreamThread,
} from "stream-chat";
import {
  Channel,
  ChannelHeader,
  MessageComposer,
  MessageList,
  Thread,
  ThreadHeader,
  WithComponents,
} from "stream-chat-react";
import type { DateSeparatorProps } from "stream-chat-react";

// The list finds date separators by the class and reads their dates from `data-date`.
const DayOnlySeparator = ({ date, floating }: DateSeparatorProps) => (
  <div
    className={`str-chat__date-separator${floating ? " str-chat__date-separator--floating" : ""}`}
    data-date={date.toISOString()}
  >
    {date.toLocaleDateString()}
  </div>
);

const ClosedReplies = () => (
  <div className="closed-replies">Replies are closed.</div>
);

const appOverrides = { DateSeparator: DayOnlySeparator };
const threadOverrides = { MessageComposerUI: ClosedReplies };

type ConversationProps = {
  channel: StreamChannel;
  thread?: StreamThread;
};

export const Conversation = ({ channel, thread }: ConversationProps) => (
  <WithComponents overrides={appOverrides}>
    <Channel channel={channel}>
      <ChannelHeader />
      <MessageList />
      <MessageComposer />
    </Channel>
    {thread && (
      <WithComponents overrides={threadOverrides}>
        <Thread thread={thread}>
          <ThreadHeader />
          <MessageList />
          <MessageComposer />
        </Thread>
      </WithComponents>
    )}
  </WithComponents>
);

Both message lists render DayOnlySeparator. Only the thread's composer renders ClosedReplies. The icons key merges icon by icon, so a nested WithComponents that sets one icon keeps the icons set above it.

Current override keys

"none" in the props column means the component receives no props: it reads what it needs from context. Apart from MessageUI and VirtualMessage, those keys are typed React.ComponentType without props, so an override whose props are required doesn't compile. Where the default takes props of its own, the SDK still passes none: an override that renders the default can pass them, as in MessageStatus: () => <MessageStatus MessageReadStatus={ReadIcon} />. A default marked "built in" is a component the SDK doesn't export.

Key Replaces Props Default
AdditionalMessageComposerActions the area next to the composer's input that holds the emoji picker: Actions none AdditionalMessageComposerActions
Attachment a message's attachments: Parts of the default message UI AttachmentProps Attachment
AttachmentFileIcon the file-type icon on file attachments FileIconProps FileIcon
AttachmentPreviewList the attachment previews in the composer: The preview set none; the default takes AttachmentPreviewListProps AttachmentPreviewList
AttachmentSelector the composer's attachment button and its menu: Actions none AttachmentSelector, and SimpleAttachmentSelector while editing a message
AttachmentSelectorInitiationButtonContents the content of the attachment button: Message composer UI none the plus icon
AttachmentUploadProgressIndicator the progress of a message attachment that is still uploading AttachmentUploadProgressIndicatorProps AttachmentUploadProgressIndicator
AudioRecorder the voice recorder in the composer: Actions none AudioRecorder
AutocompleteSuggestionItem one item of the composer's suggestion list: Message composer UI SuggestionItemProps SuggestionListItem
AutocompleteSuggestionList the composer's suggestion list: Message composer UI SuggestionListProps SuggestionList
Avatar a user's avatar. The tiles of <GroupAvatar/> keep the default Avatar: see Avatar ChannelAvatarProps Avatar, and ChannelAvatar in channel-list rows, channel management and member details
AvatarStack a row of overlapping avatars AvatarStackProps AvatarStack
BaseImage an image, with its fallback when it fails to load. BaseImage lists the images it reaches BaseImageProps BaseImage
CalloutDialog the content of a callout dialog CalloutDialogProps built in
ChannelListHeader the channel list's header: Header none; the default takes ChannelListHeaderProps ChannelListHeader
ChannelListItemActionButtons the action buttons of a channel-list row: Channel preview actions none ChannelListItemActionButtons
ChannelListItemUI a channel-list row: Channel previews ChannelListItemUIProps ChannelListItemUI
CommandChip the selected command in the composer: The input CommandChipProps CommandChip
ContextMenu every context menu: Ready-made dialogs ContextMenuProps ContextMenu
ContextMenuContent a context menu's body and submenus: Ready-made dialogs ContextMenuContentProps ContextMenuContent
CooldownTimer the slow-mode countdown in the composer: Actions none CooldownTimer
DateSeparator the date separators in message lists: Separators DateSeparatorProps DateSeparator
EditedMessagePreview the preview of the message being edited, above the composer's input: The preview set EditedMessagePreviewProps EditedMessagePreview
EmojiPicker the emoji picker button in the composer: Actions none none: register EmojiPicker from stream-chat-react/emojis
EmptyListIndicator what an empty channel list shows: List states UI none an EmptyStateIndicator for channels
EmptyStateIndicator what an empty message list shows: Message list UI EmptyStateIndicatorProps EmptyStateIndicator
EndReachedIndicator the start or the end of a channel list: List states UI { hasEnded: boolean; reached: "top" | "bottom" } renders nothing
extractDisplayInfo how a user becomes the name and image an avatar shows a function of { user }, not a component built in
FileDragAndDropContent the overlay WithDragAndDropUpload shows while files are dragged over it: WithDragAndDropUpload FileDragAndDropContentProps: { isDragRejected } FileDragAndDropContent
FileSizeIndicator a file size label FileSizeIndicatorProps FileSizeIndicator
FirstPageLoadingIndicator a channel list or the thread list loading its first page: FirstPageLoadingIndicator and ListLoadErrorIndicator none LoadingChannels
Gallery the gallery's state and navigation GalleryProps Gallery
GalleryUI the gallery's slides and buttons none GalleryUI
GiphyPreviewMessage a Giphy preview below the messages of VirtualizedMessageList, with separateGiphyPreview GiphyPreviewMessageProps, which is MessageProps GiphyPreviewMessage
HeaderComponent content at the top of MessageList, or at its headerPosition none none
icons the SDK's icons, merged icon by icon IconSlots, not a component the SDK's icons
ImagePlaceholder an image that failed to load ImagePlaceholderProps ImagePlaceholder
LinkPreviewList the link previews in the composer: The preview set none LinkPreviewList
ListItem a row of a channel list: Channel list UI { item: unknown } a ChannelListItem for the channel
ListLoadErrorIndicator a channel list or the thread list whose first page failed to load: FirstPageLoadingIndicator and ListLoadErrorIndicator ListLoadErrorIndicatorProps ListLoadErrorIndicator, with the list's text
LoadingIndicator the spinner of message lists, videos, the thread list and other parts: LoadingIndicator lists them LoadingIndicatorProps LoadingIndicator
LoadingNextPageIndicator a channel list loading its next page: List states UI { isLoading?: boolean } a LoadingIndicator while loading
MessageActions a message's actions: Message actions none MessageActions
MessageAlsoSentInChannelIndicator the "also sent in channel" mark on a reply: Parts of the default message UI none MessageAlsoSentInChannelIndicator
MessageBlocked a message blocked by moderation: Parts of the default message UI none MessageBlocked
MessageBouncePrompt the dialog for a bounced message MessageBouncePromptProps MessageBouncePrompt
MessageBubbleContent what a message's bubble holds: Bubble content none; the default takes MessageBubbleContentProps MessageBubbleContent
MessageComposerPreviews the previews above the composer's input: Previews none; the default takes MessageComposerPreviewsProps MessageComposerPreviews
MessageComposerUI the composer UI that MessageComposer renders: Message composer UI none; the default takes MessageComposerProps MessageComposerUI
MessageDeleted a deleted message, in place of its bubble: Parts of the default message UI MessageDeletedProps none
MessageDeletedBubble the bubble of a deleted message: Parts of the default message UI none MessageDeletedBubble
MessageEditedIndicator the "Edited" mark: Parts of the default message UI none; the default takes MessageEditedIndicatorProps MessageEditedIndicator
MessageListItem the li around each item of MessageList: Message list UI MessageListItemProps: className, data-index, data-message-id and data-testid, to spread onto the element li
MessageListMainPanel the panel around a message list and its notification list PropsWithChildren built in
MessageListWrapper the ul around the messages of MessageList: Message list UI MessageListWrapperProps: className ul
MessageReactions a message's reactions: Parts of the default message UI MessageReactionsProps MessageReactions
MessageReactionsDetail the dialog that lists who reacted MessageReactionsDetailProps MessageReactionsDetail
MessageRepliesCountButton the replies button on a message: Parts of the default message UI MessageRepliesCountButtonProps MessageRepliesCountButton
MessageStatus sending, sent, delivered or read: Parts of the default message UI none; the default takes MessageStatusProps MessageStatus
MessageSystem a system message: Parts of the default message UI EventComponentProps EventComponent
MessageText a message's text, also the text of an AI-generated message while StreamedMessageText streams it: Bubble content MessageTextProps MessageText
MessageTimestamp a message's timestamp and, when set, the time in the gallery header for media shared in a message: Parts of the default message UI MessageTimestampProps MessageTimestamp
MessageTranslationIndicator the "translated" mark: Parts of the default message UI TranslationIndicatorProps MessageTranslationIndicator
MessageUI a whole message, in both lists unless VirtualMessage is set: How a message is rendered none: read useMessageContext() MessageUI
Modal every modal: Modals ModalProps GlobalModal
ModalGallery a message's images, which open the gallery ModalGalleryProps ModalGallery
NewMessageNotification the "new messages" notification of a message list: Floating notifications NewMessageNotificationProps, without label NewMessageNotification
Notification one notification in a NotificationList: Replacing the list or a notification NotificationProps, with a ref Notification
NotificationAnnouncer the screen-reader announcements of notifications, rendered by Chat none; the default takes NotificationAnnouncerProps NotificationAnnouncer
NotificationList every notification list: Notification lists and panels NotificationListProps NotificationList
PinIndicator the pinned mark: Parts of the default message UI PinIndicatorProps PinIndicator
PollActions a poll's buttons none PollActions
PollContent a poll in a message none PollContent
PollCreationDialog the dialog that creates a poll: Message composer UI PollCreationDialogProps PollCreationDialog
PollCreationDialogControls the buttons at the bottom of the poll creation dialog: Message composer UI PollCreationDialogControlsProps PollCreationDialogControls
PollHeader a poll's header none PollHeader
PollOptionSelector one option of a poll PollOptionSelectorProps PollOptionSelector
ProgressIndicator the progress of an upload, in composer previews, message attachments and the voice recorder ProgressIndicatorProps CircularProgressIndicator
QuotedMessage the quoted message inside a message: Bubble content none QuotedMessage
QuotedMessagePreview the quoted message above the composer's input: The preview set none; the default takes QuotedMessagePreviewProps QuotedMessagePreview
reactionOptions the reactions users can pick ReactionOptions, not a component defaultReactionOptions
ReactionSelector the reaction picker ReactionSelectorProps ReactionSelector
ReactionSelectorExtendedList the full reaction picker in the reactions dialog the props of ReactionSelector.ExtendedList ReactionSelector.ExtendedList
RecordingPermissionDeniedNotification the notice shown when microphone access is denied RecordingPermissionDeniedNotificationProps RecordingPermissionDeniedNotification
ReminderNotification a message's reminder mark: Parts of the default message UI ReminderNotificationProps ReminderNotification
ScrollToLatestMessageButton the button of a message list that scrolls to the latest message: Floating notifications ScrollToLatestMessageButtonProps ScrollToLatestMessageButton
Search the search UI none Search
SearchBar the search input none SearchBar
SearchResults the search results pane none SearchResults
SearchResultsHeader the header of the results pane none SearchResultsHeader
SearchResultsPresearch the results pane before the first search SearchResultsPresearchProps SearchResultsPresearch
SearchSourceResultList the result list of one search source none; the default takes SearchSourceResultListProps SearchSourceResultList
SearchSourceResultListFooter the end of one source's result list none SearchSourceResultListFooter
SearchSourceResults the section of one search source SearchSourceResultsProps: { searchSource } SearchSourceResults
SearchSourceResultsEmpty a source with no results none SearchSourceResultsEmpty
SearchSourceResultsHeader the header of one source's section none built in
SearchSourceResultsLoadingIndicator a source loading results none SearchSourceResultsLoadingIndicator
SendButton the send button: Actions SendButtonProps SendButton
SendToChannelCheckbox the "also send to channel" checkbox in a thread's composer: In threads none built in
ShareLocationDialog the location-sharing dialog: Message composer UI ShareLocationDialogProps ShareLocationDialog
StartRecordingAudioButton the button that starts a voice recording: Actions StartRecordingAudioButtonProps StartRecordingAudioButton
StopAIGenerationButton the stop button while an AI is thinking or generating a reply: Actions ComponentProps<"button"> built in; null removes the button
StreamedMessageText the text of an AI-generated message: Bubble content StreamedMessageTextProps StreamedMessageText
SummarizedMessagePreview the latest-message preview of a channel-list row and of a thread-list row: Channel list UI SummarizedMessagePreviewProps SummarizedMessagePreview
TextareaComposer the composer's text input: The input none; the default takes TextareaComposerProps TextareaComposer
ThreadHead the parent message above a thread's replies: Thread UI MessageProps built in
ThreadListEmptyPlaceholder an empty thread list: List states UI none built in
ThreadListHeader the thread list's header: Header none; the default takes ThreadListHeaderProps ThreadListHeader
ThreadListItem a thread-list row: Thread list items ThreadListItemProps ThreadListItem
ThreadListItemUI the UI of a thread-list row: Thread list items ThreadListItemUIProps ThreadListItemUI
ThreadListLoadingIndicator a thread list loading its next page: List states UI none built in
ThreadListUnseenThreadsBanner the banner about threads with new replies: The unseen threads banner none built in
ThreadStart the reply count under a thread's parent message: Thread UI none ThreadStart
Timestamp the date inside timestamps and the edited mark TimestampProps built in
TypingIndicator the typing indicator of message lists: Typing indicator TypingIndicatorProps TypingIndicator in MessageList; none in VirtualizedMessageList
UnreadMessagesNotification the floating unread notification: Floating notifications UnreadMessagesNotificationProps UnreadMessagesNotification
UnreadMessagesSeparator the unread separator: Separators UnreadMessagesSeparatorProps UnreadMessagesSeparator
UploadedSizeIndicator the uploaded and total size of an upload UploadedSizeIndicatorProps UploadedSizeIndicator
VideoPlayer video playback { controls?: boolean; isPlaying?: boolean; thumbnailUrl?: string; videoUrl?: string } built in
VirtualMessage a whole message, in VirtualizedMessageList only: Message list UI none: read useMessageContext() none: MessageUI renders
VoiceRecordingPreviewSlot the voice recording preview above the composer's attachments: The preview set none; the default takes VoiceRecordingPreviewSlotProps VoiceRecordingPreviewSlot

Choosing between props and context

Use a key for a part the SDK renders, and a prop or your own children for a part you render yourself:

  • Components you render, such as ChannelHeader, ThreadHeader, MessageList and MessageComposer, have no key. Pass them props, or render something else in their place. ChannelHeader's StartContent, EndContent, Title, Subtitle and Avatar are props for this reason. The header in Channel UI shows which part each one replaces.
  • Parts the SDK renders, such as a message, the date separators or the notification list, have a key. Set it with WithComponents around the subtree that should use it.
  • Some components take a prop and read a key for the same part. The prop wins for that one instance. Gallery renders its GalleryUI prop, else the GalleryUI key, else the default. Attachment takes Image, Giphy, File and other props for the parts it renders, while the Attachment key replaces Attachment itself.

Channel and Thread render only their children, so their content is yours to compose. See Composition.

  • useComponentContext() returns the overrides in effect, or {} outside every provider.
  • useComponentContextIcons() returns every icon, with the icons overrides merged over the SDK's own. See Icons.