# Required
yarn add react-native-teleport
# Optional — install for improved keyboard handling
yarn add react-native-keyboard-controllerUpgrading 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:
- Your project is running on React Native 0.76+ (or an Expo SDK version that defaults to the New Architecture).
- The New Architecture is enabled in your project configuration.
- 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:
| Package | Minimum Version | Required? | Purpose |
|---|---|---|---|
react-native-teleport | >=0.5.4 | Yes | Portal-based overlay system for the new message menus |
react-native-keyboard-controller | >=1.20.2 | No | Smoother, animation-driven keyboard interactions |
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 prebuildafter installing.
Dependency Version Bumps
| Package | V8 Version | V9 Version | Notes |
|---|---|---|---|
stream-chat | ^9.27.2 | ^9.36.0 | Includes new server-side features (reminders, save-for-later, etc.) |
@gorhom/bottom-sheet | ^5.1.8 | 5.1.8 | Pinned to an exact version to avoid regressions |
lodash-es | 4.17.21 | 4.17.23 | Patch-level bump |
linkifyjs | ^4.3.1 | ^4.3.2 | Patch-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:
| Layer | What it Contains |
|---|---|
primitives | Low-level building blocks — shadow, radius, spacing, and typography constants (e.g. primitives.spacingSm, primitives.radiusLg). |
foundations | 99 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. |
components | 38 component-specific dimension tokens for buttons, composers, devices, icons, and message bubbles. |
semantics | 199 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 equivalentsemantics.*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
| Property | V8 Value | V9 Value | Notes |
|---|---|---|---|
screenPadding | 8 | 16 | Doubled for better visual spacing |
BASE_AVATAR_SIZE | 32 | 24 | Reduced to match new UI density |
loadingDots.spacing | 4 | primitives.spacingXxs | Now 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| Change | Details |
|---|---|
size | Now a string enum ('xs'–'2xl') instead of a pixel number |
image → imageUrl | Renamed for clarity |
name removed | Use placeholder for fallback content |
online / presenceIndicator | Removed — use the separate OnlineIndicator badge component instead |
ChannelAvatar | Moved to ui/Avatar/ChannelAvatar; now uses size='xl' by default |
GroupAvatar | Replaced 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
| Component | Purpose |
|---|---|
BadgeNotification | Unread counts and notification badges |
OnlineIndicator | User presence status (replaces Avatar's online prop) |
ErrorBadge | Error state indicators |
GiphyBadge | Giphy source badge on media |
ImgurBadge | Imgur source badge on media |
BadgeCount | Generic numeric badge |
Other New Primitives
| Component | Purpose |
|---|---|
Input | Standardized text input component |
VideoPlayIndicator | Play button overlay with size variants ('sm' / 'md' / 'lg') |
SpeedSettingsButton | Playback speed control for audio/video |
GiphyChip | Giphy 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 ModalNew 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:
| Prop | Description |
|---|---|
MessageComposerLeadingView | Left side of the composer — wraps InputButtons |
MessageComposerTrailingView | Right side of the composer — empty slot for custom trailing content |
MessageInputHeaderView | Header area — consolidates reply preview, edit header, attachments, and link previews |
MessageInputFooterView | Footer area below the input — empty slot for custom content |
MessageInputLeadingView | Leading area of the input text row |
MessageInputTrailingView | Trailing area — wraps OutputButtons (Send / Edit / Cooldown / Audio) |
InputView | The text input view itself |
messageInputFloating | boolean — enables a floating input layout (default: false) |
Removed Props
The following props are removed from Channel and MessageInputContext:
| Removed Prop | What to Use Instead |
|---|---|
CommandsButton | Commands are handled internally via the new CommandChip component |
MoreOptionsButton | Consolidated into InputButtons |
InputEditingStateHeader | Consolidated into MessageInputHeaderView |
InputReplyStateHeader | Consolidated into MessageInputHeaderView |
CommandInput | Replaced by the internal CommandChip component |
AttachmentPickerBottomSheetHandle | Removed — the attachment picker has been fully redesigned |
attachmentPickerBottomSheetHandleHeight | Removed |
CameraSelectorIcon | Replaced by AttachmentTypePickerButton |
FileSelectorIcon | Replaced by AttachmentTypePickerButton |
ImageSelectorIcon | Replaced by AttachmentTypePickerButton |
VideoRecorderSelectorIcon | Replaced by AttachmentTypePickerButton |
CreatePollIcon | Poll creation is handled internally |
AttachmentPickerError | Removed |
AttachmentPickerErrorImage | Removed |
AttachmentUploadProgressIndicator | Split into six granular indicators (see Upload Indicators) |
cooldownEndsAt | Cooldown is now managed internally by OutputButtons |
selectedPicker | Removed from context — use useAttachmentPickerState() hook |
toggleAttachmentPicker | Replaced by openAttachmentPicker / closeAttachmentPicker |
New Upload Indicator Components
The single AttachmentUploadProgressIndicator is replaced by six specific components, giving you finer control over each upload state:
| Component | Purpose |
|---|---|
FileUploadInProgressIndicator | Progress indicator for file uploads |
FileUploadRetryIndicator | Retry button for failed file uploads |
FileUploadNotSupportedIndicator | Indicator for unsupported file types |
ImageUploadInProgressIndicator | Progress indicator for image uploads |
ImageUploadRetryIndicator | Retry button for failed image uploads |
ImageUploadNotSupportedIndicator | Indicator for unsupported images |
OutputButtons Component
A new OutputButtons component manages the trailing action buttons using priority-based rendering with animated transitions (ZoomIn/ZoomOut, 200ms):
| Priority | Condition | Button Shown |
|---|---|---|
| 1 | AI streaming is active | StopMessageStreamingButton |
| 2 | User is editing a message or command | EditButton |
| 3 | Slow-mode cooldown is active | CooldownTimer |
| 4 | Audio recording enabled, no text/attachments | StartAudioRecordingButton |
| 5 | Default | SendButton |
Component Path Changes
| V8 Path | V9 Path |
|---|---|
MessageInput/AttachButton | MessageInput/components/InputButtons/AttachButton |
MessageInput/SendButton | MessageInput/components/OutputButtons/SendButton |
MessageInput/CooldownTimer | MessageInput/components/OutputButtons/CooldownTimer |
MessageInput/InputButtons | MessageInput/components/InputButtons |
MessageInput/AttachmentUploadPreviewList | MessageInput/components/AttachmentPreview/AttachmentUploadPreviewList |
New MessageInput Components
| Component | Description |
|---|---|
CommandChip | Displays the active slash command with a dismiss button |
EditButton | Confirm button shown when editing a message |
LinkPreviewList | Renders URL preview cards inline in the input area |
MicPositionContext | Context provider for audio recording microphone position |
MessageInputContext Changes
Removed Values
| Removed Value | What to Use Instead |
|---|---|
cooldownEndsAt | Managed internally in OutputButtons |
selectedPicker | useAttachmentPickerState() hook |
toggleAttachmentPicker | openAttachmentPicker / closeAttachmentPicker |
getMessagesGroupStyles | Removed — grouping logic is now internal |
legacyImageViewerSwipeBehaviour | Removed — the legacy image viewer is no longer supported |
Added Values
| New Value | Type | Description |
|---|---|---|
audioRecorderManager | AudioRecorderManager | Manages 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 |
messageInputFloating | boolean | Whether the input is using floating layout |
messageInputHeightStore | MessageInputHeightStore | State store for tracking input height |
createPollOptionGap | number | Gap between poll options in creation UI |
Modified Values
| Value | V8 Type | V9 Type |
|---|---|---|
takeAndUploadImage | () => Promise<void> | () => Promise<{askToOpenSettings?; canceled?}> |
CooldownTimer | ComponentType<CooldownTimerProps> | ComponentType (no props — self-contained) |
AudioRecordingPreview | ComponentType<AudioRecordingPreviewProps> | ComponentType (no props — self-contained) |
VideoAttachmentUploadPreview | ComponentType<FileAttachmentUploadPreviewProps> | ComponentType<VideoAttachmentUploadPreviewProps> |
AudioAttachment Changes
The audio playback system has been rewritten to use a centralized player model.
Removed Props
| Removed Prop | Notes |
|---|---|
onLoad | Replaced by the useAudioPlayer hook |
onPlayPause | Replaced by the useAudioPlayer hook |
onProgress | Replaced by the useAudioPlayer hook |
titleMaxLength | Removed — use showTitle boolean instead |
Added Props
| New Prop | Type | Description |
|---|---|---|
showTitle | boolean | Controls whether the audio title is shown |
containerStyle | ViewStyle | Style override for the container |
indicator | ReactElement | Custom indicator element |
styles | object | Granular style overrides |
Hook Rename
| V8 Hook | V9 Hook |
|---|---|
useAudioController | useAudioRecorder |
useAudioPlayerControl | useAudioPlayer |
MessageList Changes
New Props
| Prop | Type | Description |
|---|---|---|
animateLayout | boolean | Enables layout animations for message insertion/removal (default: true) |
messageInputFloating | boolean | Tells the list whether the input is in floating mode |
messageInputHeightStore | state store | State store for coordinating with the input's height |
InlineDateSeparator | Component | Customizable inline date separator rendered between messages |
InlineUnreadIndicator | Component | Customizable inline unread indicator rendered at the unread boundary |
Message | Component | Override the default message component |
attachmentPickerStore | state store | State store for the attachment picker |
Removed Props
| Prop | Notes |
|---|---|
isListActive | Removed |
legacyImageViewerSwipeBehaviour | Removed — the legacy image viewer is no longer supported |
setMessages | Removed — use the centralized state store instead |
selectedPicker | Replaced by attachmentPickerStore |
setSelectedPicker | Replaced by attachmentPickerStore |
Modified Props
| Prop | V8 Type | V9 Type |
|---|---|---|
additionalFlatListProps | Partial<FlatListProps<LocalMessage>> | Partial<FlatListProps<MessageListItemWithNeighbours>> |
setFlatListRef | FlatListType<LocalMessage> | FlatListType<MessageListItemWithNeighbours> |
channelUnreadState | Direct state value | Replaced 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
| Component | Description |
|---|---|
ScrollToBottomButton | Redesigned with animated entrance — uses the new Button and BadgeNotification components |
StickyHeader | Sticky date header that tracks the scroll position |
UnreadMessagesNotification | Redesigned with a two-button layout: "Jump to unread" and dismiss |
MessagesContext Changes
Removed Values
| Removed Value | What to Use Instead |
|---|---|
AttachmentActions | Removed — actions are now inline on attachments |
Card | Replaced by UrlPreview with new URLPreviewProps |
CardCover / CardFooter / CardHeader | Removed — the card component is redesigned as UrlPreview |
ImageReloadIndicator | Removed |
MessageEditedTimestamp | Folded into the message footer |
getMessagesGroupStyles | Removed — grouping is handled internally |
legacyImageViewerSwipeBehaviour | Removed |
Added Values
| New Value | Type | Description |
|---|---|---|
urlPreviewType | 'compact' | 'full' | Controls URL preview style (compact card vs. full embed) |
URLPreviewCompact | ComponentType<URLPreviewCompactProps> | Compact URL preview component |
FilePreview | ComponentType<FilePreviewProps> | Standalone file preview component |
MessageReminderHeader | ComponentType<MessageReminderHeaderProps> | Header shown on reminded messages |
MessageSavedForLaterHeader | ComponentType<MessageSavedForLaterHeaderProps> | Header shown on saved-for-later messages |
SentToChannelHeader | ComponentType<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 |
ReactionListClustered | Component | Clustered reaction list display |
ReactionListItem | Component | Individual reaction item |
ReactionListItemWrapper | Component | Wrapper for reaction items |
ReactionListCountItem | Component | Reaction count display |
UnsupportedAttachment | ComponentType<UnsupportedAttachmentProps> | Fallback renderer for unsupported/custom attachment types |
Modified Values
| Value | V8 Type | V9 Type |
|---|---|---|
UrlPreview | ComponentType<CardProps> | ComponentType<URLPreviewProps> |
MessageSimple | ComponentType<MessageSimpleProps> | ComponentType<MessageSimpleProps & { ref?: RefObject<View> }> |
MessageHeader | Optional ComponentType<MessageFooterProps> | Required ComponentType<MessageHeaderProps> |
Note:
MessageHeaderis 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 Prop | V9 Source |
|---|---|
alignment | useMessageContext() |
message | useMessageContext() or optional message prop |
date | message.created_at |
isDeleted | message.type === 'deleted' |
lastGroupMessage | useMessageContext() |
members | useMessageContext() |
MessageStatus | useMessagesContext() |
otherAttachments | useMessageContext() |
showMessageStatus | useMessageContext() |
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
| Prop | Type | Default | Description |
|---|---|---|---|
messageInputFloating | boolean | false | Enables the floating message input layout |
handleBlockUser | function | — | Callback for blocking a user |
reactionListType | 'clustered' | 'default' | 'clustered' | Switches between clustered and default reaction lists |
urlPreviewType | 'full' | 'compact' | 'full' | Controls URL preview display style |
onAlsoSentToChannelHeaderPress | function | — | Press handler for thread "also sent to channel" header |
asyncMessagesLockDistance | number | 50 | Audio recording gesture: lock distance threshold |
asyncMessagesMinimumPressDuration | number | 500 | Audio recording gesture: minimum press duration (ms) |
asyncMessagesMultiSendEnabled | boolean | true | Whether multiple audio messages can be queued |
asyncMessagesSlideToCancelDistance | number | 75 | Audio recording gesture: slide-to-cancel distance |
createPollOptionGap | number | — | Gap between poll options in the creation UI |
MessageReminderHeader | Component | — | Custom header for message reminders |
MessageSavedForLaterHeader | Component | — | Custom header for saved messages |
SentToChannelHeader | Component | — | Custom header for "also sent to channel" thread messages |
ReactionListClustered | Component | — | Custom clustered reaction list |
ReactionListCountItem | Component | — | Custom reaction count item |
ReactionListItem | Component | — | Custom reaction list item |
ReactionListItemWrapper | Component | — | Custom reaction list item wrapper |
URLPreviewCompact | Component | — | Custom compact URL preview |
FilePreview | Component | — | Custom file preview component |
UnsupportedAttachment | Component | — | Fallback 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 Prop | Notes |
|---|---|
legacyImageViewerSwipeBehaviour | Legacy image viewer is removed |
isAttachmentEqual | Removed |
MessageEditedTimestamp | Folded into the message footer |
ImageReloadIndicator | Removed |
AttachmentActions | Removed — actions are inline on attachments |
Card / CardCover / CardFooter / CardHeader | Replaced by UrlPreview / URLPreviewCompact |
AttachmentPickerIOSSelectMorePhotos | Removed |
| All attachment picker selector icons | See MessageInput — Removed Props |
Modified Default Values
| Prop | V8 Default | V9 Default | Impact |
|---|---|---|---|
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 |
numberOfAttachmentImagesToLoadPerCall | 60 | 25 | Reduced for better performance on lower-end devices |
attachmentPickerBottomSheetHeight | vh(45) (viewport-based) | disableAttachmentPicker ? 72 : 333 (fixed) | Switched from viewport-relative to fixed pixel values |
attachmentSelectionBarHeight | 52 | 72 | Increased for better touch targets |
Action required: If your UI depends on
'text'rendering before'attachments', explicitly pass the V8 order array tomessageContentOrder.
ChannelPreview Changes
The channel preview components have been redesigned with new hooks and a restructured layout.
Key API Change: latestMessagePreview → lastMessage
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
| Component | Description |
|---|---|
ChannelDetailsBottomSheet | Bottom sheet overlay for channel details and actions |
ChannelLastMessagePreview | Formatted last message preview with attachment/poll awareness |
ChannelMessagePreviewDeliveryStatus | Delivery status indicator in the channel preview |
ChannelPreviewMutedStatus | Muted state indicator with configurable position |
ChannelPreviewTypingIndicator | Typing indicator shown in the channel preview |
Removed Components
| Removed Component | Notes |
|---|---|
ChannelAvatar | Replaced by ChannelAvatar from ui/Avatar/ (different API) |
PreviewAvatar | Removed from context — use ChannelAvatar with size='xl' |
New Props
| Prop | Type | Description |
|---|---|---|
mutedStatusPosition | 'inlineTitle' | 'trailingBottom' | Where the muted icon appears in the channel preview |
New Hooks
| Hook | Description |
|---|---|
useChannelPreviewDraftMessage | Access draft message data for a channel |
useChannelPreviewPollLabel | Get a formatted label for the last poll |
useChannelTypingState | Observe 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 Hook | V9 Hook |
|---|---|
useMutedUsers (from Chat) | useClientMutedUsers |
Attachment Components
Renamed Components
| V8 Component | V9 Component | Notes |
|---|---|---|
AudioAttachment | Audio | Renamed; file moved to Audio/ subdirectory |
Card | UrlPreview | Renamed with new URLPreviewProps interface |
Removed Components
| Removed Component | Notes |
|---|---|
AttachmentActions | Removed — actions are now handled inline on attachments |
ImageReloadIndicator | Removed |
AttachmentUnsupportedIndicator | Removed |
New Components
| Component | Description |
|---|---|
URLPreviewCompact | Compact URL preview with card-style layout |
UnsupportedAttachment | Replaces the old unsupported indicator with a full component |
AttachmentPicker Overhaul
The attachment picker has been completely redesigned with a simpler, more extensible architecture.
Removed:
AttachmentPickerBottomSheetHandleAttachmentPickerError/AttachmentPickerErrorImageCameraSelectorIcon/FileSelectorIcon/ImageSelectorIcon/VideoRecorderSelectorIconAttachmentPickerIOSSelectMorePhotosAttachmentPickerItem
Added:
| Component | Description |
|---|---|
AttachmentPickerContent | Main content area of the redesigned picker |
AttachmentMediaPicker | Media selection UI (photos and videos) |
AttachmentTypePickerButton | Unified 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
| Prop | Type | Description |
|---|---|---|
MessageOverlayBackground | React.ComponentType | Custom background component for the message overlay |
Removed Props
| Removed Prop | What to Use Instead |
|---|---|
imageGalleryGridHandleHeight | Removed |
imageGalleryGridSnapPoints | Removed |
imageGalleryCustomComponents | Replaced by direct component props (see below) |
Image Gallery Customization — Flattened
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:
ImageGalleryAssettype replaces the oldPhototype.- Gallery configuration (
autoPlayVideo,giphyVersion) moves from props toImageGalleryOptionsin the state store. - Three utility functions are exported:
isViewableImageAttachment,isViewableVideoAttachment,isViewableGiphyAttachment.
// V8
<Gallery autoPlayVideo={true} giphyVersion="original" />;
// V9
const { imageGalleryStateStore } = useImageGalleryContext();
imageGalleryStateStore.openImageGallery(/* ... */);Removed
| Removed | Notes |
|---|---|
imageGalleryCustomComponents | Replaced by direct component props |
autoPlayVideo (as prop) | Moved to ImageGalleryOptions in state store |
giphyVersion (as prop) | Moved to ImageGalleryOptions in state store |
imageGalleryGridSnapPoints | Removed |
imageGalleryGridHandleHeight | Removed |
ImageGalleryOverlay | Removed |
ImageGridHandle | Removed |
legacyImageViewerSwipeBehaviour | Removed |
setMessages / setSelectedMessage | Use imageGalleryStateStore instead |
Added
| Added | Description |
|---|---|
ImageGalleryVideoControls | Component prop for video playback controls |
ImageGalleryVideoControl | Video controls UI component |
useImageGalleryVideoPlayer | Hook for managing video player state |
Message Components
New Components
| Component | Description |
|---|---|
MessageHeader | Consolidated message header — now required in MessagesContext |
MessageBlocked | UI for blocked messages |
MessageSwipeContent | Content revealed on message swipe |
MessageTextContainer | Wrapper for message text with consistent styling |
ReactionListClustered | Clustered reaction list display (new default style) |
ReactionListItem | Individual reaction item component |
ReactionListItemWrapper | Wrapper for reaction items |
Removed Components
| Removed Component | Notes |
|---|---|
MessageEditedTimestamp | Folded into the message footer component |
MessagePreview | Replaced 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:
| Hook | Description |
|---|---|
useMessageDeliveryStatus | Returns delivery status data for a message preview |
useGroupedAttachments | Returns grouped attachment data for a message |
useMessagePreviewIcon | Determines the appropriate icon for a preview |
useMessagePreviewText | Formats 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:
VideoPlayerclass withVideoPlayerState,VideoDescriptor,VideoPlayerOptionstypesDEFAULT_PLAYBACK_RATESandINITIAL_VIDEO_PLAYER_STATEconstants
VideoPlayerPool
Pool management for multiple concurrent video players:
VideoPlayerPoolclass withVideoPlayerPoolStatetype
ImageGalleryStateStore
Centralized state for the image gallery (replaces in-component state):
ImageGalleryStateStoreclassImageGalleryAsset,ImageGalleryState,ImageGalleryOptionstypesisViewableImageAttachment,isViewableVideoAttachment,isViewableGiphyAttachmentutilities
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
| Hook | Description |
|---|---|
useAttachmentPickerState | Manages attachment picker open/closed state (replaces context-based approach) |
useAudioRecorder | Audio recording lifecycle (replaces useAudioController) |
useAudioPlayer | Audio playback control (replaces useAudioPlayerControl) |
useMessageDeliveryStatus | Message delivery status for previews |
useGroupedAttachments | Grouped attachment data for message previews |
useMessagePreviewIcon | Icon selection logic for message previews |
useMessagePreviewText | Text formatting for message previews |
useImageGalleryVideoPlayer | Video player state within the image gallery |
useMessageComposer | Direct access to message composer state and methods |
Renamed Hooks
| V8 Hook | V9 Hook |
|---|---|
useAudioController | useAudioRecorder |
useAudioPlayerControl | useAudioPlayer |
useMutedUsers | useClientMutedUsers |
New Contexts
| Context | Description |
|---|---|
BottomSheetContext | Provides 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
| Icon | Description |
|---|---|
BlockUser | Block user action |
Plus | Add/create action |
Minus | Remove action |
ArrowShareLeft | Share/forward action |
Bell | Notification/reminder bell |
Bookmark | Save for later / bookmark |
Checkmark | Confirmation checkmark |
CommandsIcon | Slash commands |
FilePickerIcon | File 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.
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
EmojiViewerButtoncomponent for expanding the full emoji list. - Reactions filter to
isMainreactions by default. - Haptic feedback on reaction selection.
useHasOwnReactionhook 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,composerContainercommandInput(closeButton,container,text)commandsButton,moreOptionsButton,optionsContainereditingBoxContainer,editingBoxHeader,editingBoxHeaderTitle,editingStateHeaderreplyContainersearchIcon,sendRightIcon,sendUpIconaudioRecordingButton(container,micIcon)uploadProgressIndicator(container,indicatorColor,overlay)cooldownTimer.container(onlytextremains)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(withlinkContainer,linkIcon,container,imageWrapper,dismissWrapper,thumbnail,wrapper,metadataContainer,text,titleText)
Modified keys:
attachmentUploadPreviewList: from{ filesFlatList, imagesFlatList, wrapper }to{ flatList, itemSeparator }imageAttachmentUploadPreview:itemContainer→container, addedwrappervideoAttachmentUploadPreview: from{ recorderIconContainer, recorderIcon, itemContainer, upload }to{ durationContainer, durationText }
messageList Theme
Added keys:
inlineDateSeparatorContainerunreadUnderlayContainerscrollToBottomButtonContainerstickyHeaderContainerunreadMessagesNotificationContainer
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:
containersimplified fromViewStyle & { borderRadiusL, borderRadiusS }toViewStyle- Removed:
deletedContainer,deletedContainerInner,deletedMetaText,deletedText,editedLabel,messageUser,metaContainer,receiverMessageBackgroundColor,senderMessageBackgroundColor - Added:
contentContainer
New sub-components:
deleted—containerInner,deletedText,containerfooter—container,name,editedTextbubble—reactionListTopContainer,contentContainer,wrapper,errorContainersavedForLaterHeader—container,labelreminderHeader—container,label,dot,timesentToChannelHeader—container,label,dot,linkunsupportedAttachment—container,details,titlecontentContainer,leftAlignItems,rightAlignItemsmessageGroupedSingleStyles,messageGroupedBottomStyles,messageGroupedTopStyles,messageGroupedMiddleStyles
avatarWrapper: Removed leftAlign, rightAlign
card → UrlPreview:
- Removed:
authorName,authorNameContainer,authorNameFooter,authorNameFooterContainer,authorNameMask,noURI,playButtonStyle,playIcon - Added:
linkPreview,linkPreviewText - New sub-component
compactUrlPreviewwithwrapper,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:
reactionListItem—reactionCount,iconreactionListClustered—contentContainer,reactionCount,iconStyle,iconreactionListItemWrapper—wrapper,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:
| Property | V8 | V9 |
|---|---|---|
gridHeight | 195 | 192 |
maxHeight | 300 | 192 |
minHeight | 100 | 120 |
minWidth | 170 | 120 |
channelPreview Theme
Removed: avatar, checkAllIcon, checkIcon, row, mutedStatus (old structure with height, iconStyle, width)
Added:
messageDeliveryStatus—container,text,checkAllIcon,checkIcon,timeIconlowerRow,upperRow,statusContainer,titleContainer,wrappertypingIndicatorPreview—container,textmessagePreview—container,subtitlemessageexpanded withsubtitle,errorText,draftText
channelListSkeleton Theme
Completely restructured:
- Removed:
background,gradientStart,gradientStop,height,maskFillColor - Added:
avatar,badge,content,headerRow,subtitle,textContainer,title animationTimechanged from1800to1000
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:buttonContainer→contentContainerpoll.createContent: AddedoptionCardWrapperand expanded settings withdescription,optionCardContent,optionCardSwitchforaddComment,anonymousPoll,multipleAnswers,suggestOptionpoll.message.option: Removed color strings (progressBarEmptyFill,progressBarVotedFill, etc.), addedinfo,header,votesText,progressBarContainerprogressControl: RemovedfilledColortypingIndicator: AddedloadingDotsBubble,avatarStackContainerattachmentPicker: RemovederrorButtonText,errorContainer,errorText; addedcontent(container,infoContainer,text)audioAttachment: AddedcenterContainer,audioInfothreadListUnreadBanner:touchableWrapperrenamed tocontainerthread.newThread: Restructured to includecontainer- 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-controllerUpdate 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… |
|---|---|
CommandsButton | Internal CommandChip (automatic) |
MoreOptionsButton | InputButtons |
InputEditingStateHeader | MessageInputHeaderView |
InputReplyStateHeader | MessageInputHeaderView |
toggleAttachmentPicker | openAttachmentPicker / closeAttachmentPicker |
selectedPicker | useAttachmentPickerState() 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
useAudioController→useAudioRecorder. - Rename
useAudioPlayerControl→useAudioPlayer. - Remove
onLoad,onPlayPause,onProgresscallbacks fromAudioAttachment— use theuseAudioPlayerhook instead.
8. Update Image Gallery Customizations
Replace the imageGalleryCustomComponents nested object on OverlayProvider with direct component props (ImageGalleryHeader, ImageGalleryFooter, ImageGalleryVideoControls, ImageGalleryGrid).
9. Update ChannelPreview Customizations
- Replace
latestMessagePreviewwithlastMessagein any customPreviewStatusorPreviewMessagecomponents. - Replace
ChannelAvatarusage with the newChannelAvatarfromui/Avatar/. - Rename
useMutedUsers→useClientMutedUsers. - If you customized
MessageHeader, stop relying on the old explicit prop bag fromMessageSimple. Read data fromuseMessageContext()/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 keysmessageSimple— new sub-components (bubble,footer,deleted, etc.)channelPreview— new layout keys (upperRow,lowerRow, etc.)reply— completely redesignedthreadListItem— 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.
- React Native New Architecture Required
- New Peer Dependencies
- Dependency Version Bumps
- Design Token System
- New Base UI Component Library
- MessageInput — Complete Redesign
- MessageInputContext Changes
- AudioAttachment Changes
- MessageList Changes
- MessagesContext Changes
- Channel Component Changes
- ChannelPreview Changes
- Attachment Components
- OverlayProvider Changes
- ImageGallery Changes
- Message Components
- State Store Additions
- New Hooks
- New Contexts
- Icons Changes
- MessageMenu (Context Menu)
- Theme Changes
- Migration Checklist
- 1. Install New Dependencies
- 2. Update Avatar Usage
- 3. Update MessageInput Customizations
- 4. Update Attachment Picker Customizations
- 5. Update Upload Progress Indicators
- 6. Update URL Preview Customizations
- 7. Update Audio Hooks and Props
- 8. Update Image Gallery Customizations
- 9. Update ChannelPreview Customizations
- 10. Update Theme Overrides
- 11. Migrate Colors to Semantic Tokens
- 12. Update Icon Imports
- 13. Update FlatList Types
- 14. Review messageContentOrder
- 15. Update Message Action Types