This is beta documentation for Stream Chat React Native SDK v9. For the latest stable version, see the latest version (v8) .

Upgrading to v9

Version 9 of the Stream Chat React Native SDK is a ground-up redesign of the entire UI layer. Every visual component has been rethought to deliver a modern, polished chat experience out of the box — backed by a new design token system, a slot-based composition architecture for the message input, a centralized state store system, and a brand-new base UI component library.

If you are upgrading from V8, expect to touch theme overrides, component imports, and any code that customizes the message input, attachment picker, channel preview, or overlay system. This guide walks through every breaking change, highlights what replaced what, and ends with a concrete checklist you can follow.


React Native New Architecture Required

V9 supports the React Native New Architecture only. The old architecture (Paper renderer and the legacy bridge) is no longer supported. Before upgrading to V9, ensure that:

  1. Your project is running on React Native 0.76+ (or an Expo SDK version that defaults to the New Architecture).
  2. The New Architecture is enabled in your project configuration.
  3. All other third-party native modules you depend on are New Architecture compatible.

If your project is still on the old architecture, you must migrate to the New Architecture first. Refer to the React Native New Architecture guide for instructions.


New Peer Dependencies

V9 introduces one new required peer dependency and one optional one:

PackageMinimum VersionRequired?Purpose
react-native-teleport>=0.5.4YesPortal-based overlay system for the new message menus
react-native-keyboard-controller>=1.20.2NoSmoother, animation-driven keyboard interactions
# Required
yarn add react-native-teleport

# Optional — install for improved keyboard handling
yarn add react-native-keyboard-controller

react-native-keyboard-controller is entirely optional. The SDK works without it, but when installed it provides smoother keyboard animations and more reliable keyboard height tracking. You can add it at any time.

Expo users: Both packages ship with config plugins. Run npx expo prebuild after installing.


Dependency Version Bumps

PackageV8 VersionV9 VersionNotes
stream-chat^9.27.2^9.36.0Includes new server-side features (reminders, save-for-later, etc.)
@gorhom/bottom-sheet^5.1.85.1.8Pinned to an exact version to avoid regressions
lodash-es4.17.214.17.23Patch-level bump
linkifyjs^4.3.1^4.3.2Patch-level bump

Design Token System

V8 used ad-hoc color values and scattered style constants. V9 replaces all of this with a layered design token system that makes theming consistent and predictable.

The New theme/ Module

The SDK now exports a theme/ module with four layers:

LayerWhat it Contains
primitivesLow-level building blocks — shadow, radius, spacing, and typography constants (e.g. primitives.spacingSm, primitives.radiusLg).
foundations99 color properties across 10 palettes (blue, cyan, green, lime, neutral, purple, red, slate, violet, yellow) at intensities 50–900, plus 20 layout sizes, 11 radii, 13 spacing values, 6 stroke widths, and 27 typography properties.
components38 component-specific dimension tokens for buttons, composers, devices, icons, and message bubbles.
semantics199 purpose-driven color properties (backgrounds, borders, text, accents, avatars, badges, buttons, chat bubbles, controls, inputs, etc.), shipped in three variants: light, dark, and high-contrast-light.

The defaultTheme object now exposes a top-level semantics property alongside the existing colors:

const theme = useTheme();
const { semantics, colors } = theme;

// Semantic tokens are named by purpose, not by hue
const bgColor = semantics.backgroundElevationElevation1;
const borderColor = semantics.borderCoreDefault;
const textColor = semantics.textPrimary;

Migration tip: Wherever you were using raw colors.* values (e.g. colors.grey, colors.white_snow), prefer the equivalent semantics.* token. Semantic tokens automatically adapt across light, dark, and high-contrast themes.

Color Changes

The colors type no longer includes an index signature ({ [key: string]: string }). If you were storing custom color keys on the colors object, move them to the semantics object or extend the theme type.

Default Value Changes

PropertyV8 ValueV9 ValueNotes
screenPadding816Doubled for better visual spacing
BASE_AVATAR_SIZE3224Reduced to match new UI density
loadingDots.spacing4primitives.spacingXxsNow references a design token

New Base UI Component Library

V9 introduces a ui/ component library that provides standardized, token-driven UI primitives. These replace the older ad-hoc components and give you building blocks that are consistent with the SDK's new design language.

Avatar

The Avatar and GroupAvatar components have been moved from components/Avatar/ to components/ui/Avatar/. The old exports are removed.

V8:

import { Avatar, GroupAvatar } from "stream-chat-react-native";
// Props: image, name, online, presenceIndicator, size (number)

V9:

import { Avatar } from "stream-chat-react-native";
// Props: size ('2xl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs'),
//        imageUrl, placeholder, showBorder, backgroundColor, style
ChangeDetails
sizeNow a string enum ('xs''2xl') instead of a pixel number
imageimageUrlRenamed for clarity
name removedUse placeholder for fallback content
online / presenceIndicatorRemoved — use the separate OnlineIndicator badge component instead
ChannelAvatarMoved to ui/Avatar/ChannelAvatar; now uses size='xl' by default
GroupAvatarReplaced by AvatarGroup and AvatarStack in the new library

Button

A new standardized Button component with variant, type, and size props:

import { Button } from "stream-chat-react-native";

<Button
  variant="primary" // 'primary' | 'secondary' | 'destructive'
  type="solid" // 'solid' | 'outline' | 'ghost' | 'liquidGlass'
  size="md" // 'sm' | 'md' | 'lg'
  LeadingIcon={SendRight}
  label="Send"
  disabled={false}
/>;

Badge Components

ComponentPurpose
BadgeNotificationUnread counts and notification badges
OnlineIndicatorUser presence status (replaces Avatar's online prop)
ErrorBadgeError state indicators
GiphyBadgeGiphy source badge on media
ImgurBadgeImgur source badge on media
BadgeCountGeneric numeric badge

Other New Primitives

ComponentPurpose
InputStandardized text input component
VideoPlayIndicatorPlay button overlay with size variants ('sm' / 'md' / 'lg')
SpeedSettingsButtonPlayback speed control for audio/video
GiphyChipGiphy indicator chip for message input

MessageInput — Complete Redesign

The message input underwent the most significant transformation in V9. It moves from a flat, prop-heavy component to a slot-based composition architecture that is easier to customize and extend.

Architecture Change

V8: A single component with many inline conditional renders. Buttons (Send, AudioRecord, Cooldown, Commands, MoreOptions) were rendered directly in the component body and customized via individual component props.

V9: A slotted layout with clearly defined regions that you can replace independently:

MessageInput
├── MessageComposerLeadingView    ← wraps InputButtons (attach, etc.)
├── Main Input Area
│   ├── MessageInputHeaderView    ← reply preview, edit header, attachments, link previews
│   ├── AudioRecordingPreview / AudioRecordingInProgress / InputView
├── MessageInputTrailingView      ← wraps OutputButtons (send, edit, cooldown, audio)
├── MessageComposerTrailingView   ← empty slot for your own custom content
├── AutoCompleteSuggestionList
└── Poll Creation Modal

New useMessageComposer Hook

V9 exposes a useMessageComposer() hook that gives you direct access to the composer's internal state without going through context:

const messageComposer = useMessageComposer();
const { attachmentManager, textComposer, editedMessage, channel, hasCommands } =
  messageComposer;

New Slot Props

These composition slot components can be passed to the Channel component to customize regions of the input:

PropDescription
MessageComposerLeadingViewLeft side of the composer — wraps InputButtons
MessageComposerTrailingViewRight side of the composer — empty slot for custom trailing content
MessageInputHeaderViewHeader area — consolidates reply preview, edit header, attachments, and link previews
MessageInputFooterViewFooter area below the input — empty slot for custom content
MessageInputLeadingViewLeading area of the input text row
MessageInputTrailingViewTrailing area — wraps OutputButtons (Send / Edit / Cooldown / Audio)
InputViewThe text input view itself
messageInputFloatingboolean — enables a floating input layout (default: false)

Removed Props

The following props are removed from Channel and MessageInputContext:

Removed PropWhat to Use Instead
CommandsButtonCommands are handled internally via the new CommandChip component
MoreOptionsButtonConsolidated into InputButtons
InputEditingStateHeaderConsolidated into MessageInputHeaderView
InputReplyStateHeaderConsolidated into MessageInputHeaderView
CommandInputReplaced by the internal CommandChip component
AttachmentPickerBottomSheetHandleRemoved — the attachment picker has been fully redesigned
attachmentPickerBottomSheetHandleHeightRemoved
CameraSelectorIconReplaced by AttachmentTypePickerButton
FileSelectorIconReplaced by AttachmentTypePickerButton
ImageSelectorIconReplaced by AttachmentTypePickerButton
VideoRecorderSelectorIconReplaced by AttachmentTypePickerButton
CreatePollIconPoll creation is handled internally
AttachmentPickerErrorRemoved
AttachmentPickerErrorImageRemoved
AttachmentUploadProgressIndicatorSplit into six granular indicators (see Upload Indicators)
cooldownEndsAtCooldown is now managed internally by OutputButtons
selectedPickerRemoved from context — use useAttachmentPickerState() hook
toggleAttachmentPickerReplaced by openAttachmentPicker / closeAttachmentPicker

New Upload Indicator Components

The single AttachmentUploadProgressIndicator is replaced by six specific components, giving you finer control over each upload state:

ComponentPurpose
FileUploadInProgressIndicatorProgress indicator for file uploads
FileUploadRetryIndicatorRetry button for failed file uploads
FileUploadNotSupportedIndicatorIndicator for unsupported file types
ImageUploadInProgressIndicatorProgress indicator for image uploads
ImageUploadRetryIndicatorRetry button for failed image uploads
ImageUploadNotSupportedIndicatorIndicator for unsupported images

OutputButtons Component

A new OutputButtons component manages the trailing action buttons using priority-based rendering with animated transitions (ZoomIn/ZoomOut, 200ms):

PriorityConditionButton Shown
1AI streaming is activeStopMessageStreamingButton
2User is editing a message or commandEditButton
3Slow-mode cooldown is activeCooldownTimer
4Audio recording enabled, no text/attachmentsStartAudioRecordingButton
5DefaultSendButton

Component Path Changes

V8 PathV9 Path
MessageInput/AttachButtonMessageInput/components/InputButtons/AttachButton
MessageInput/SendButtonMessageInput/components/OutputButtons/SendButton
MessageInput/CooldownTimerMessageInput/components/OutputButtons/CooldownTimer
MessageInput/InputButtonsMessageInput/components/InputButtons
MessageInput/AttachmentUploadPreviewListMessageInput/components/AttachmentPreview/AttachmentUploadPreviewList

New MessageInput Components

ComponentDescription
CommandChipDisplays the active slash command with a dismiss button
EditButtonConfirm button shown when editing a message
LinkPreviewListRenders URL preview cards inline in the input area
MicPositionContextContext provider for audio recording microphone position

MessageInputContext Changes

Removed Values

Removed ValueWhat to Use Instead
cooldownEndsAtManaged internally in OutputButtons
selectedPickeruseAttachmentPickerState() hook
toggleAttachmentPickeropenAttachmentPicker / closeAttachmentPicker
getMessagesGroupStylesRemoved — grouping logic is now internal
legacyImageViewerSwipeBehaviourRemoved — the legacy image viewer is no longer supported

Added Values

New ValueTypeDescription
audioRecorderManagerAudioRecorderManagerManages audio recording lifecycle and state
startVoiceRecording() => Promise<boolean>Start a voice recording
stopVoiceRecording() => Promise<void>Stop the current voice recording
deleteVoiceRecording() => Promise<void>Delete the current voice recording
uploadVoiceRecording(multiSendEnabled) => Promise<void>Upload the recorded voice message
messageInputFloatingbooleanWhether the input is using floating layout
messageInputHeightStoreMessageInputHeightStoreState store for tracking input height
createPollOptionGapnumberGap between poll options in creation UI

Modified Values

ValueV8 TypeV9 Type
takeAndUploadImage() => Promise<void>() => Promise<{askToOpenSettings?; canceled?}>
CooldownTimerComponentType<CooldownTimerProps>ComponentType (no props — self-contained)
AudioRecordingPreviewComponentType<AudioRecordingPreviewProps>ComponentType (no props — self-contained)
VideoAttachmentUploadPreviewComponentType<FileAttachmentUploadPreviewProps>ComponentType<VideoAttachmentUploadPreviewProps>

AudioAttachment Changes

The audio playback system has been rewritten to use a centralized player model.

Removed Props

Removed PropNotes
onLoadReplaced by the useAudioPlayer hook
onPlayPauseReplaced by the useAudioPlayer hook
onProgressReplaced by the useAudioPlayer hook
titleMaxLengthRemoved — use showTitle boolean instead

Added Props

New PropTypeDescription
showTitlebooleanControls whether the audio title is shown
containerStyleViewStyleStyle override for the container
indicatorReactElementCustom indicator element
stylesobjectGranular style overrides

Hook Rename

V8 HookV9 Hook
useAudioControlleruseAudioRecorder
useAudioPlayerControluseAudioPlayer

MessageList Changes

New Props

PropTypeDescription
animateLayoutbooleanEnables layout animations for message insertion/removal (default: true)
messageInputFloatingbooleanTells the list whether the input is in floating mode
messageInputHeightStorestate storeState store for coordinating with the input's height
InlineDateSeparatorComponentCustomizable inline date separator rendered between messages
InlineUnreadIndicatorComponentCustomizable inline unread indicator rendered at the unread boundary
MessageComponentOverride the default message component
attachmentPickerStorestate storeState store for the attachment picker

Removed Props

PropNotes
isListActiveRemoved
legacyImageViewerSwipeBehaviourRemoved — the legacy image viewer is no longer supported
setMessagesRemoved — use the centralized state store instead
selectedPickerReplaced by attachmentPickerStore
setSelectedPickerReplaced by attachmentPickerStore

Modified Props

PropV8 TypeV9 Type
additionalFlatListPropsPartial<FlatListProps<LocalMessage>>Partial<FlatListProps<MessageListItemWithNeighbours>>
setFlatListRefFlatListType<LocalMessage>FlatListType<MessageListItemWithNeighbours>
channelUnreadStateDirect state valueReplaced by channelUnreadStateStore

The FlatList item type changed from LocalMessage to MessageListItemWithNeighbours. Each item now carries references to its preceding and following messages, enabling smarter grouping and rendering.

New Sub-Components

ComponentDescription
ScrollToBottomButtonRedesigned with animated entrance — uses the new Button and BadgeNotification components
StickyHeaderSticky date header that tracks the scroll position
UnreadMessagesNotificationRedesigned with a two-button layout: "Jump to unread" and dismiss

MessagesContext Changes

Removed Values

Removed ValueWhat to Use Instead
AttachmentActionsRemoved — actions are now inline on attachments
CardReplaced by UrlPreview with new URLPreviewProps
CardCover / CardFooter / CardHeaderRemoved — the card component is redesigned as UrlPreview
ImageReloadIndicatorRemoved
MessageEditedTimestampFolded into the message footer
getMessagesGroupStylesRemoved — grouping is handled internally
legacyImageViewerSwipeBehaviourRemoved

Added Values

New ValueTypeDescription
urlPreviewType'compact' | 'full'Controls URL preview style (compact card vs. full embed)
URLPreviewCompactComponentType<URLPreviewCompactProps>Compact URL preview component
FilePreviewComponentType<FilePreviewProps>Standalone file preview component
MessageReminderHeaderComponentType<MessageReminderHeaderProps>Header shown on reminded messages
MessageSavedForLaterHeaderComponentType<MessageSavedForLaterHeaderProps>Header shown on saved-for-later messages
SentToChannelHeaderComponentType<SentToChannelHeaderProps>Header for thread replies that were also sent to the channel
handleBlockUser(user) => Promise<void>Handler for blocking a user from the message menu
reactionListType'clustered' | 'segmented'Controls reaction list rendering style
ReactionListClusteredComponentClustered reaction list display
ReactionListItemComponentIndividual reaction item
ReactionListItemWrapperComponentWrapper for reaction items
ReactionListCountItemComponentReaction count display
UnsupportedAttachmentComponentType<UnsupportedAttachmentProps>Fallback renderer for unsupported/custom attachment types

Modified Values

ValueV8 TypeV9 Type
UrlPreviewComponentType<CardProps>ComponentType<URLPreviewProps>
MessageSimpleComponentType<MessageSimpleProps>ComponentType<MessageSimpleProps & { ref?: RefObject<View> }>
MessageHeaderOptional ComponentType<MessageFooterProps>Required ComponentType<MessageHeaderProps>

Note: MessageHeader is now a required value in the context. If you were relying on it being optional, make sure your custom provider supplies a component.

MessageHeader redesign

In v8, MessageSimple passed a richer runtime prop bag into custom headers, including alignment, date, isDeleted, lastGroupMessage, members, message, MessageStatus, otherAttachments, and showMessageStatus.

In v9, the public prop surface is limited to message?, and the default MessageHeader reads its data and subcomponents from useMessageContext() and useMessagesContext() instead. If you customized MessageHeader, move that logic into hooks rather than relying on the old explicit props.

V8 PropV9 Source
alignmentuseMessageContext()
messageuseMessageContext() or optional message prop
datemessage.created_at
isDeletedmessage.type === 'deleted'
lastGroupMessageuseMessageContext()
membersuseMessageContext()
MessageStatususeMessagesContext()
otherAttachmentsuseMessageContext()
showMessageStatususeMessageContext()

If your old customization was only about pinned, reminder, saved-for-later, or sent-to-channel header UI, prefer overriding MessagePinnedHeader, MessageReminderHeader, MessageSavedForLaterHeader, or SentToChannelHeader directly.


Channel Component Changes

New Props

PropTypeDefaultDescription
messageInputFloatingbooleanfalseEnables the floating message input layout
handleBlockUserfunctionCallback for blocking a user
reactionListType'clustered' | 'default''clustered'Switches between clustered and default reaction lists
urlPreviewType'full' | 'compact''full'Controls URL preview display style
onAlsoSentToChannelHeaderPressfunctionPress handler for thread "also sent to channel" header
asyncMessagesLockDistancenumber50Audio recording gesture: lock distance threshold
asyncMessagesMinimumPressDurationnumber500Audio recording gesture: minimum press duration (ms)
asyncMessagesMultiSendEnabledbooleantrueWhether multiple audio messages can be queued
asyncMessagesSlideToCancelDistancenumber75Audio recording gesture: slide-to-cancel distance
createPollOptionGapnumberGap between poll options in the creation UI
MessageReminderHeaderComponentCustom header for message reminders
MessageSavedForLaterHeaderComponentCustom header for saved messages
SentToChannelHeaderComponentCustom header for "also sent to channel" thread messages
ReactionListClusteredComponentCustom clustered reaction list
ReactionListCountItemComponentCustom reaction count item
ReactionListItemComponentCustom reaction list item
ReactionListItemWrapperComponentCustom reaction list item wrapper
URLPreviewCompactComponentCustom compact URL preview
FilePreviewComponentCustom file preview component
UnsupportedAttachmentComponentFallback renderer for unsupported/custom attachment types

All the MessageComposer*View and MessageInput*View slot props from the MessageInput section are also available on Channel.

Removed Props

Removed PropNotes
legacyImageViewerSwipeBehaviourLegacy image viewer is removed
isAttachmentEqualRemoved
MessageEditedTimestampFolded into the message footer
ImageReloadIndicatorRemoved
AttachmentActionsRemoved — actions are inline on attachments
Card / CardCover / CardFooter / CardHeaderReplaced by UrlPreview / URLPreviewCompact
AttachmentPickerIOSSelectMorePhotosRemoved
All attachment picker selector iconsSee MessageInput — Removed Props

Modified Default Values

PropV8 DefaultV9 DefaultImpact
messageContentOrder['quoted_reply', 'gallery', 'files', 'poll', 'ai_text', 'text', 'attachments', 'location']['quoted_reply', 'gallery', 'files', 'poll', 'ai_text', 'attachments', 'text', 'location']'attachments' and 'text' are swapped
numberOfAttachmentImagesToLoadPerCall6025Reduced for better performance on lower-end devices
attachmentPickerBottomSheetHeightvh(45) (viewport-based)disableAttachmentPicker ? 72 : 333 (fixed)Switched from viewport-relative to fixed pixel values
attachmentSelectionBarHeight5272Increased for better touch targets

Action required: If your UI depends on 'text' rendering before 'attachments', explicitly pass the V8 order array to messageContentOrder.


ChannelPreview Changes

The channel preview components have been redesigned with new hooks and a restructured layout.

Key API Change: latestMessagePreviewlastMessage

In V8, ChannelPreview exposed a latestMessagePreview object with pre-formatted preview data. In V9, this is replaced with lastMessage — the raw last message object — and specialized hooks for formatting:

// V8
const { latestMessagePreview } = useChannelPreviewContext();
const previewText = latestMessagePreview?.messageObject?.text;

// V9
const { lastMessage } = useChannelPreviewContext();
const previewText = lastMessage?.text;

New Components

ComponentDescription
ChannelDetailsBottomSheetBottom sheet overlay for channel details and actions
ChannelLastMessagePreviewFormatted last message preview with attachment/poll awareness
ChannelMessagePreviewDeliveryStatusDelivery status indicator in the channel preview
ChannelPreviewMutedStatusMuted state indicator with configurable position
ChannelPreviewTypingIndicatorTyping indicator shown in the channel preview

Removed Components

Removed ComponentNotes
ChannelAvatarReplaced by ChannelAvatar from ui/Avatar/ (different API)
PreviewAvatarRemoved from context — use ChannelAvatar with size='xl'

New Props

PropTypeDescription
mutedStatusPosition'inlineTitle' | 'trailingBottom'Where the muted icon appears in the channel preview

New Hooks

HookDescription
useChannelPreviewDraftMessageAccess draft message data for a channel
useChannelPreviewPollLabelGet a formatted label for the last poll
useChannelTypingStateObserve who is currently typing in the channel

Hook Export Changes

Individual hook exports from ChannelPreview/hooks/, ChannelList/hooks/, and Chat/hooks/ are consolidated into barrel exports. The hooks themselves are still available, but you import from the barrel:

// V8
import { useChannelPreviewDisplayName } from "stream-chat-react-native/ChannelPreview/hooks/useChannelPreviewDisplayName";

// V9
import { useChannelPreviewDisplayName } from "stream-chat-react-native";

Hook Rename

V8 HookV9 Hook
useMutedUsers (from Chat)useClientMutedUsers

Attachment Components

Renamed Components

V8 ComponentV9 ComponentNotes
AudioAttachmentAudioRenamed; file moved to Audio/ subdirectory
CardUrlPreviewRenamed with new URLPreviewProps interface

Removed Components

Removed ComponentNotes
AttachmentActionsRemoved — actions are now handled inline on attachments
ImageReloadIndicatorRemoved
AttachmentUnsupportedIndicatorRemoved

New Components

ComponentDescription
URLPreviewCompactCompact URL preview with card-style layout
UnsupportedAttachmentReplaces the old unsupported indicator with a full component

AttachmentPicker Overhaul

The attachment picker has been completely redesigned with a simpler, more extensible architecture.

Removed:

  • AttachmentPickerBottomSheetHandle
  • AttachmentPickerError / AttachmentPickerErrorImage
  • CameraSelectorIcon / FileSelectorIcon / ImageSelectorIcon / VideoRecorderSelectorIcon
  • AttachmentPickerIOSSelectMorePhotos
  • AttachmentPickerItem

Added:

ComponentDescription
AttachmentPickerContentMain content area of the redesigned picker
AttachmentMediaPickerMedia selection UI (photos and videos)
AttachmentTypePickerButtonUnified type selector button replacing all individual icon components

OverlayProvider Changes

The overlay system has been rearchitected to use a portal-based approach powered by react-native-teleport. This eliminates the need for complex z-index management and provides smoother overlay animations.

New Architecture

The OverlayProvider now wraps its children with a PortalProvider and renders a MessageOverlayHostLayer for the new portal-based message overlay. This means message context menus and reaction pickers render in a true overlay portal rather than within the component tree.

New Props

PropTypeDescription
MessageOverlayBackgroundReact.ComponentTypeCustom background component for the message overlay

Removed Props

Removed PropWhat to Use Instead
imageGalleryGridHandleHeightRemoved
imageGalleryGridSnapPointsRemoved
imageGalleryCustomComponentsReplaced by direct component props (see below)

The nested imageGalleryCustomComponents object is replaced by direct component props for simpler customization:

V8:

<OverlayProvider
  imageGalleryCustomComponents={{
    footer: { Component: CustomFooter },
    header: { Component: CustomHeader },
    grid: { Component: CustomGrid },
    gridHandle: { Component: CustomGridHandle },
  }}
>

V9:

<OverlayProvider
  ImageGalleryHeader={CustomHeader}
  ImageGalleryFooter={CustomFooter}
  ImageGalleryVideoControls={CustomVideoControls}
  ImageGalleryGrid={CustomGrid}
>

New Context Value

OverlayContextValue now includes overlayOpacity (SharedValue<number>) — a Reanimated shared value you can use to drive custom overlay animations.


ImageGallery Changes

The image gallery has been refactored to use a centralized state store instead of in-component state.

State Store

A new ImageGalleryStateStore replaces in-component state management:

  • ImageGalleryAsset type replaces the old Photo type.
  • Gallery configuration (autoPlayVideo, giphyVersion) moves from props to ImageGalleryOptions in the state store.
  • Three utility functions are exported: isViewableImageAttachment, isViewableVideoAttachment, isViewableGiphyAttachment.
// V8
<Gallery autoPlayVideo={true} giphyVersion="original" />;

// V9
const { imageGalleryStateStore } = useImageGalleryContext();
imageGalleryStateStore.openImageGallery(/* ... */);

Removed

RemovedNotes
imageGalleryCustomComponentsReplaced by direct component props
autoPlayVideo (as prop)Moved to ImageGalleryOptions in state store
giphyVersion (as prop)Moved to ImageGalleryOptions in state store
imageGalleryGridSnapPointsRemoved
imageGalleryGridHandleHeightRemoved
ImageGalleryOverlayRemoved
ImageGridHandleRemoved
legacyImageViewerSwipeBehaviourRemoved
setMessages / setSelectedMessageUse imageGalleryStateStore instead

Added

AddedDescription
ImageGalleryVideoControlsComponent prop for video playback controls
ImageGalleryVideoControlVideo controls UI component
useImageGalleryVideoPlayerHook for managing video player state

Message Components

New Components

ComponentDescription
MessageHeaderConsolidated message header — now required in MessagesContext
MessageBlockedUI for blocked messages
MessageSwipeContentContent revealed on message swipe
MessageTextContainerWrapper for message text with consistent styling
ReactionListClusteredClustered reaction list display (new default style)
ReactionListItemIndividual reaction item component
ReactionListItemWrapperWrapper for reaction items

Removed Components

Removed ComponentNotes
MessageEditedTimestampFolded into the message footer component
MessagePreviewReplaced by specialized hooks (see below)

MessagePinnedHeader still exists in v9. It is now rendered as part of the consolidated MessageHeader flow alongside reminder, saved-for-later, and sent-to-channel headers.

MessagePreview → Hooks

The MessagePreview component is removed in favor of composable hooks:

HookDescription
useMessageDeliveryStatusReturns delivery status data for a message preview
useGroupedAttachmentsReturns grouped attachment data for a message
useMessagePreviewIconDetermines the appropriate icon for a preview
useMessagePreviewTextFormats the preview text for a message

State Store Additions

V9 adds four new centralized state store modules that follow the same observable pattern used elsewhere in the SDK:

VideoPlayer

Mirrors the existing audio player architecture for video:

  • VideoPlayer class with VideoPlayerState, VideoDescriptor, VideoPlayerOptions types
  • DEFAULT_PLAYBACK_RATES and INITIAL_VIDEO_PLAYER_STATE constants

VideoPlayerPool

Pool management for multiple concurrent video players:

  • VideoPlayerPool class with VideoPlayerPoolState type

ImageGalleryStateStore

Centralized state for the image gallery (replaces in-component state):

  • ImageGalleryStateStore class
  • ImageGalleryAsset, ImageGalleryState, ImageGalleryOptions types
  • isViewableImageAttachment, isViewableVideoAttachment, isViewableGiphyAttachment utilities

MessageOverlayStore

Complete state management for the portal-based overlay system:

  • Store instances: overlayStore, closingPortalLayoutsStore
  • Lifecycle functions: openOverlay, closeOverlay, scheduleActionOnClose, finalizeCloseOverlay
  • Layout management: setOverlayMessageH, setOverlayTopH, setOverlayBottomH, bumpOverlayLayoutRevision
  • Portal management: createClosingPortalLayoutRegistrationId, setClosingPortalLayout, clearClosingPortalLayout
  • Hooks: useOverlayController, useIsOverlayClosing, useIsOverlayActive, useClosingPortalHostBlacklistState, useShouldTeleportToClosingPortal, useClosingPortalHostBlacklist, useClosingPortalLayouts

New Hooks

HookDescription
useAttachmentPickerStateManages attachment picker open/closed state (replaces context-based approach)
useAudioRecorderAudio recording lifecycle (replaces useAudioController)
useAudioPlayerAudio playback control (replaces useAudioPlayerControl)
useMessageDeliveryStatusMessage delivery status for previews
useGroupedAttachmentsGrouped attachment data for message previews
useMessagePreviewIconIcon selection logic for message previews
useMessagePreviewTextText formatting for message previews
useImageGalleryVideoPlayerVideo player state within the image gallery
useMessageComposerDirect access to message composer state and methods

Renamed Hooks

V8 HookV9 Hook
useAudioControlleruseAudioRecorder
useAudioPlayerControluseAudioPlayer
useMutedUsersuseClientMutedUsers

New Contexts

ContextDescription
BottomSheetContextProvides bottom sheet control (close() method)

Icons Changes

V9 significantly overhauls the icon set: many legacy icons are removed, and new icons are added to support the redesigned UI.

New Icons

IconDescription
BlockUserBlock user action
PlusAdd/create action
MinusRemove action
ArrowShareLeftShare/forward action
BellNotification/reminder bell
BookmarkSave for later / bookmark
CheckmarkConfirmation checkmark
CommandsIconSlash commands
FilePickerIconFile picker trigger

Removed Icons

If you were importing any of these icons directly, you will need to provide your own icon components.

File type icons: CSV, DOCX, HTML, MD, ODT, PPT, PPTX, RAR, RTF, SEVEN_Z, TAR, TXT, XLS, XLSX

Reaction icons: LOLReaction, LoveReaction, ThumbsDownReaction, ThumbsUpReaction, WutReaction

Navigation / UI icons: ArrowLeft, ArrowUp, AtMentions, Attach, Back, ChatIcon, CheckSend, CircleClose, Down, DownloadCloud, DragHandle, Error, Folder, GenericFile, Group, Imgur, Lightning, Link, Lock, MailOpen, MenuPointVertical, MessageBubble, Mic, Notification, PinHeader, SendCheck, SendPoll, SendUp, Unpin, UserMinus, Warning


MessageMenu (Context Menu)

The message context menu has been rebuilt around the current overlay system and its dedicated reaction and action components.

Although `MessageMenu` still exists in the public surface in `v9-latest`, the active runtime overlay path no longer renders it. If you customized `MessageMenu` in v8, migrate that work to `MessageReactionPicker`, `MessageActionList`, `MessageActionListItem`, and `MessageUserReactions` instead.

ActionType Union

The ActionType union has been expanded with blockUser:

type ActionType =
  | "banUser"
  | "blockUser" // new in V9
  | "copyMessage"
  | "deleteMessage"
  | "deleteForMeMessage"
  | "editMessage"
  | "flagMessage"
  | "markUnread"
  | "muteUser"
  | "pinMessage"
  | "selectReaction"
  | "reply"
  | "retry"
  | "quotedReply"
  | "threadReply"
  | "unpinMessage";

MessageActionType Structure

Actions now include a type field that separates standard actions from destructive ones — the menu renders them in distinct groups with a visual separator:

type MessageActionType = {
  action: () => void;
  actionType: ActionType | string;
  title: string;
  icon?: React.ReactElement;
  titleStyle?: StyleProp<TextStyle>;
  type: "standard" | "destructive";
};

Reaction Picker Changes

  • Emoji picker uses a 7-column grid layout.
  • New EmojiViewerButton component for expanding the full emoji list.
  • Reactions filter to isMain reactions by default.
  • Haptic feedback on reaction selection.
  • useHasOwnReaction hook for highlighting already-reacted emojis.

Theme Changes

The theme structure has undergone extensive changes across nearly every component. Below are the most impactful changes — review these carefully if you have custom theme overrides.

messageInput Theme

Removed keys:

  • attachmentSeparator, autoCompleteInputContainer, composerContainer
  • commandInput (closeButton, container, text)
  • commandsButton, moreOptionsButton, optionsContainer
  • editingBoxContainer, editingBoxHeader, editingBoxHeaderTitle, editingStateHeader
  • replyContainer
  • searchIcon, sendRightIcon, sendUpIcon
  • audioRecordingButton (container, micIcon)
  • uploadProgressIndicator (container, indicatorColor, overlay)
  • cooldownTimer.container (only text remains)
  • imageUploadPreview.flatList

Added keys:

  • Layout: wrapper, contentContainer, inputContainer, inputBoxWrapper
  • Buttons: inputButtonsContainer, outputButtonsContainer, editButton, editButtonContainer, audioRecordingButtonContainer, cooldownButtonContainer
  • Floating: floatingWrapper, inputFloatingContainer
  • Upload indicators: fileUploadInProgressIndicator, fileUploadRetryIndicator, fileUploadNotSupportedIndicator, imageUploadInProgressIndicator, imageUploadRetryIndicator, imageUploadNotSupportedIndicator
  • Link previews: linkPreviewList (with linkContainer, linkIcon, container, imageWrapper, dismissWrapper, thumbnail, wrapper, metadataContainer, text, titleText)

Modified keys:

  • attachmentUploadPreviewList: from { filesFlatList, imagesFlatList, wrapper } to { flatList, itemSeparator }
  • imageAttachmentUploadPreview: itemContainercontainer, added wrapper
  • videoAttachmentUploadPreview: from { recorderIconContainer, recorderIcon, itemContainer, upload } to { durationContainer, durationText }

messageList Theme

Added keys:

  • inlineDateSeparatorContainer
  • unreadUnderlayContainer
  • scrollToBottomButtonContainer
  • stickyHeaderContainer
  • unreadMessagesNotificationContainer

Removed from scrollToBottomButton: touchable, wrapper, chevronColor

Modified unreadMessagesNotification:

  • Removed: closeButtonContainer, closeIcon, text
  • Added: leftButtonContainer, rightButtonContainer

messageSimple Theme

This section has the most extensive changes.

content:

  • container simplified from ViewStyle & { borderRadiusL, borderRadiusS } to ViewStyle
  • Removed: deletedContainer, deletedContainerInner, deletedMetaText, deletedText, editedLabel, messageUser, metaContainer, receiverMessageBackgroundColor, senderMessageBackgroundColor
  • Added: contentContainer

New sub-components:

  • deletedcontainerInner, deletedText, container
  • footercontainer, name, editedText
  • bubblereactionListTopContainer, contentContainer, wrapper, errorContainer
  • savedForLaterHeadercontainer, label
  • reminderHeadercontainer, label, dot, time
  • sentToChannelHeadercontainer, label, dot, link
  • unsupportedAttachmentcontainer, details, title
  • contentContainer, leftAlignItems, rightAlignItems
  • messageGroupedSingleStyles, messageGroupedBottomStyles, messageGroupedTopStyles, messageGroupedMiddleStyles

avatarWrapper: Removed leftAlign, rightAlign

cardUrlPreview:

  • Removed: authorName, authorNameContainer, authorNameFooter, authorNameFooterContainer, authorNameMask, noURI, playButtonStyle, playIcon
  • Added: linkPreview, linkPreviewText
  • New sub-component compactUrlPreview with wrapper, container, cardCover, cardFooter, title, description, linkPreview, linkPreviewText

giphy:

  • Removed: buttonContainer, cancel, giphyHeaderTitle, selectionContainer, send, shuffle, title
  • Added: actionButtonContainer, actionButton, actionButtonText, imageIndicatorContainer

reactionListBottom: Restructured from { contentContainer, item: { container, countText, filledBackgroundColor, icon, iconFillColor, iconSize, iconUnFillColor, unfilledBackgroundColor } } to { contentContainer, columnWrapper, rowSeparator }

New reaction list theme keys:

  • reactionListItemreactionCount, icon
  • reactionListClusteredcontentContainer, reactionCount, iconStyle, icon
  • reactionListItemWrapperwrapper, container

reactionListTop: Restructured from { container, item: { container, icon, iconFillColor, iconSize, iconUnFillColor, reactionSize }, position } to { container, contentContainer, list, position }. Default position changed from 16 to 8.

replies:

  • Removed: avatar, avatarContainerMultiple, avatarContainerSingle, leftAvatarsContainer, leftCurve, rightAvatarsContainer, rightCurve, avatarSize
  • Added: content, avatarStackContainer

status:

  • Removed: readByCount, statusContainer
  • Added: container

Gallery defaults changed:

PropertyV8V9
gridHeight195192
maxHeight300192
minHeight100120
minWidth170120

channelPreview Theme

Removed: avatar, checkAllIcon, checkIcon, row, mutedStatus (old structure with height, iconStyle, width)

Added:

  • messageDeliveryStatuscontainer, text, checkAllIcon, checkIcon, timeIcon
  • lowerRow, upperRow, statusContainer, titleContainer, wrapper
  • typingIndicatorPreviewcontainer, text
  • messagePreviewcontainer, subtitle
  • message expanded with subtitle, errorText, draftText

channelListSkeleton Theme

Completely restructured:

  • Removed: background, gradientStart, gradientStop, height, maskFillColor
  • Added: avatar, badge, content, headerRow, subtitle, textContainer, title
  • animationTime changed from 1800 to 1000

reply Theme

Completely redesigned:

  • Removed: fileAttachmentContainer, imageAttachment, markdownStyles, messageContainer, secondaryText, textContainer, videoThumbnail
  • Added: audioIcon, dismissWrapper, fileIcon, leftContainer, locationIcon, linkIcon, photoIcon, pollIcon, rightContainer, title, subtitle, subtitleContainer, videoIcon, wrapper, messagePreview

threadListItem Theme

Completely restructured:

  • Removed: boldText, contentRow, contentTextWrapper, headerRow, infoRow, parentMessagePreviewContainer, parentMessageText, touchableWrapper, unreadBubbleText
  • Added: wrapper, container, content, channelName, lowerRow, messageRepliesText, messagePreview, messagePreviewDeliveryStatus

Other Theme Changes

  • poll.answersList: buttonContainercontentContainer
  • poll.createContent: Added optionCardWrapper and expanded settings with description, optionCardContent, optionCardSwitch for addComment, anonymousPoll, multipleAnswers, suggestOption
  • poll.message.option: Removed color strings (progressBarEmptyFill, progressBarVotedFill, etc.), added info, header, votesText, progressBarContainer
  • progressControl: Removed filledColor
  • typingIndicator: Added loadingDotsBubble, avatarStackContainer
  • attachmentPicker: Removed errorButtonText, errorContainer, errorText; added content (container, infoContainer, text)
  • audioAttachment: Added centerContainer, audioInfo
  • threadListUnreadBanner: touchableWrapper renamed to container
  • thread.newThread: Restructured to include container
  • New top-level theme keys: channelDetailsMenu, threadListSkeleton

Migration Checklist

Follow these steps in order to migrate your project from V8 to V9:

1. Install New Dependencies

# Required
yarn add react-native-teleport

# Optional — for improved keyboard handling
yarn add react-native-keyboard-controller

Update stream-chat to ^9.36.0 and pin @gorhom/bottom-sheet to 5.1.8.

2. Update Avatar Usage

Replace Avatar with numeric size → new Avatar with string enum ('xs' through '2xl'). Rename image to imageUrl. Replace GroupAvatar with AvatarGroup or AvatarStack.

3. Update MessageInput Customizations

Replace removed props with the new slot-based components:

If you used…Replace with…
CommandsButtonInternal CommandChip (automatic)
MoreOptionsButtonInputButtons
InputEditingStateHeaderMessageInputHeaderView
InputReplyStateHeaderMessageInputHeaderView
toggleAttachmentPickeropenAttachmentPicker / closeAttachmentPicker
selectedPickeruseAttachmentPickerState() hook

4. Update Attachment Picker Customizations

Replace individual selector icons (CameraSelectorIcon, FileSelectorIcon, etc.) with AttachmentTypePickerButton. Remove references to AttachmentPickerBottomSheetHandle, AttachmentPickerError, and AttachmentPickerErrorImage.

5. Update Upload Progress Indicators

Replace AttachmentUploadProgressIndicator with the six granular indicators (FileUploadInProgressIndicator, FileUploadRetryIndicator, FileUploadNotSupportedIndicator, ImageUploadInProgressIndicator, ImageUploadRetryIndicator, ImageUploadNotSupportedIndicator).

6. Update URL Preview Customizations

Replace Card / CardProps with UrlPreview / URLPreviewProps. Use the urlPreviewType prop on Channel to switch between 'full' and 'compact' modes.

7. Update Audio Hooks and Props

  • Rename useAudioControlleruseAudioRecorder.
  • Rename useAudioPlayerControluseAudioPlayer.
  • Remove onLoad, onPlayPause, onProgress callbacks from AudioAttachment — use the useAudioPlayer hook instead.

Replace the imageGalleryCustomComponents nested object on OverlayProvider with direct component props (ImageGalleryHeader, ImageGalleryFooter, ImageGalleryVideoControls, ImageGalleryGrid).

9. Update ChannelPreview Customizations

  • Replace latestMessagePreview with lastMessage in any custom PreviewStatus or PreviewMessage components.
  • Replace ChannelAvatar usage with the new ChannelAvatar from ui/Avatar/.
  • Rename useMutedUsersuseClientMutedUsers.
  • If you customized MessageHeader, stop relying on the old explicit prop bag from MessageSimple. Read data from useMessageContext() / useMessagesContext() instead, or override the dedicated header components (MessagePinnedHeader, MessageReminderHeader, MessageSavedForLaterHeader, SentToChannelHeader).

10. Update Theme Overrides

Review any custom theme overrides against the Theme Changes section. The most impacted areas are:

  • messageInput — completely restructured layout keys
  • messageSimple — new sub-components (bubble, footer, deleted, etc.)
  • channelPreview — new layout keys (upperRow, lowerRow, etc.)
  • reply — completely redesigned
  • threadListItem — completely restructured

11. Migrate Colors to Semantic Tokens

Replace raw colors.* usage with semantics.* tokens where available. This ensures your customizations adapt correctly across light, dark, and high-contrast themes.

12. Update Icon Imports

Replace any removed icon imports with custom alternatives. See Icons Changes for the full removal list.

13. Update FlatList Types

If you use additionalFlatListProps or setFlatListRef, update your types from LocalMessage to MessageListItemWithNeighbours.

14. Review messageContentOrder

The default order now places 'attachments' before 'text'. If your UI depends on the V8 order, pass it explicitly:

<Channel
  messageContentOrder={['quoted_reply', 'gallery', 'files', 'poll', 'ai_text', 'text', 'attachments', 'location']}
>

15. Update Message Action Types

If you customize message actions, note the new 'blockUser' action type and the type: 'standard' | 'destructive' classification that controls visual grouping in the menu.