Skip to content

v15.0.0

Latest

Choose a tag to compare

@stream-ci-bot stream-ci-bot released this 06 Nov 16:08

stream-chat-react v15.0.0

v15 rebuilds the React SDK on stream-chat v10. Components read their state from the client's state stores and paginators instead of React contexts that copied channel state. Layout and navigation are now composable slots. Every message, composer and channel-list surface can be customized through action sets and component slots. The release also adds a new AI components entry point, an i18n layer with typed keys, and a tree-shakeable ESM build.

Important

v15 requires stream-chat@^10.0.0 and has many breaking changes. Before you upgrade, read the v14 → v15 migration guide. Every break is listed in the breaking changes reference, and the translation changes have their own i18n migration guide. Because v15 also moves to stream-chat v10, follow the stream-chat v9 → v10 guide as well.


✨ Highlights

Built on stream-chat v10 state

  • ChannelStateContext, ChannelActionContext and TypingContext have been removed. Components now read from the client's stores: use useChannel() for the channel, useMessagePaginator() for messages, and useStateStore(channel.state, selector) for any other channel state.
  • MessageList and VirtualizedMessageList get their messages from (thread ?? channel).messagePaginator. This covers jumping to a message or to the first unread message, loading in both directions, and the unread snapshot.
  • ChannelList is driven by a ChannelPaginator registered with client.channelManager. Ordering, filtering and handling of incoming channels are configured in stream-chat, not through ChannelList props.
  • Request handlers for send, update, delete and mark-read are registered once on the client through client.config. The Channel / Thread request props are gone.

New layout and navigation (stream-chat-react/slot-layout)

  • ChatView has been rebuilt around layout slots. You declare views, layouts and slotRenderers, and render open entities with <Slot>, <ChannelSlot> and <ThreadSlot>.
  • Workspace navigation (useWorkspaceNavigation(), WorkspaceNavigationProvider, useCloseThread()) handles opening channels and threads from channel lists, search results, thread lists and reply buttons. It works panel-aware inside ChatView, and you can provide your own outside it.
  • Channel and Thread follow the same pattern: each takes an instance prop and renders its children. Thread no longer needs a ThreadProvider, and neither component remounts when its instance changes.
  • New stream-chat-react/slot-geometry entry point.

AI components (stream-chat-react/ai-components)

  • Agent conversations, reply steps, tool approvals and sign-in flows.
  • Generated UI, with A2UI and OpenUI renderers, themed from the AI design tokens. The renderer packages (@a2ui/*, @openuidev/*) are optional peer dependencies, so you install them only if you use generated UI.
  • Voice agent visualizations (VoiceWave, VoiceGlow) and useHeardText to pace text with voice output.

Customization

  • Action sets everywhere. Message actions are configured with messageActionSet and each item's isVisible. The channel members header actions use the same shape (Component, placement: 'dropdown', isVisible).
  • Composer previews are a configurable set (defaultMessageComposerPreviewSet). You can also supply the composer used for message edits.
  • Message UI overrides go through one slot: MessageUI via WithComponents.
  • ComponentContext slots are typed by the props they receive. Overrides now apply everywhere the SDK renders that component, including link previews, galleries, quoted messages, poll vote lists and thread list items.
  • Icons are available as ComponentContext overrides. ChannelHeader gets a Title slot. Channel, thread and list headers take StartContent / EndContent props.

Messages and composer

  • Messages that are still sending show live upload progress for their attachments.
  • Only one voice message plays at a time across the whole app.
  • A poll message also renders its text and attachments, with the quoted message above the poll.
  • Submit with messageComposer.send() / update() or useMessageComposerSubmitFn(). They return 'sent' | 'nothing-to-send' | 'failed'.
  • Failed uploads are retried in place through AttachmentManager.uploadFile. Voice recordings start with a pending upload state.
  • SimpleAttachmentSelector and the plain upload button follow the composer's file rules, including customCdn. A new StandaloneButton is available.
  • Mention handling is built on mention entities, and renderText(text, options) takes them through options.messageMentionEntities.

Connectivity

  • New useWSConnectionState() and useNetworkConnectionState() hooks.
  • The lost-connection banner tells a socket drop ("Reconnecting…") apart from the device being offline ("Waiting for network…").

i18n

  • The translation runtime is shared with React Native through @stream-io/i18n.
  • Translation keys are namespaced and type-checked, so t() is strictly typed.
  • Only English is bundled, which removes about 112 KB gzip (27%) from the bundle. Register other languages yourself.

Accessibility, performance and platform

  • ChannelList renders a listbox with option items and accepts listboxProps. ChatView's selector is a navigation landmark with aria-current.
  • The ESM build emits one module per source file, so bundlers can tree-shake the SDK.
  • useStateStore provides getServerSnapshot, so server rendering works.
  • Local unread counts are supported.

⚠️ Breaking changes

These are the most common changes. The breaking changes reference has all 100+ entries, with a migration for each.

Package

  • The stream-chat peer dependency is now ^10.0.0. dayjs and i18next are no longer direct dependencies; @stream-io/i18n and @stream-io/state-store are added. Import StateStore from @stream-io/state-store, and make sure the app resolves only one copy.
  • ChatView and its helpers moved to stream-chat-react/slot-layout.
  • @stream-io/transliterate is no longer an optional dependency. AIStates is now exported from stream-chat. Unused exports were removed: Root, Header, UploadIcon, BinIcon, PauseIcon and PlayIcon.
  • Importing the SDK now types channel.data.custom.name / .image. Remove your own declarations of these fields on CustomChannelData.

Chat, layout and navigation

  • Window is removed. ChatView.Channels, ChatView.Threads and ChatView.ThreadAdapter are replaced by slots. activeChatView is renamed to activeView.
  • ChatContext no longer exposes channel, setActiveChannel, channelsQueryState or latestMessageDatesByChannels. Selecting a channel goes through workspace navigation, and outside ChatView it does nothing until you provide a navigation.
  • The options prop of useCreateChatClient is now config and takes the stream-chat configuration tree ({ client: { … } }). useChat dropped its i18n params, and Chat.defaultLanguage is removed.
  • channelPaginatorsOrchestrator is renamed to channelManager.

Channel

  • Channel requires a channel prop and no longer queries or watches the channel. Call channel.watch() yourself before rendering it; channels from ChannelList are already watched. initializeOnMount, channelQueryOptions and getChannel are removed, EmptyPlaceholder is replaced by ChannelPlaceholder, and Channel no longer renders its own loading or error state.
  • Channel no longer marks the channel read on mount (markReadOnMount), no longer writes document.title, and no longer reloads on reconnect, because the client reloads activated channels itself. A custom surface that doesn't render <Channel> must call channel.activate().
  • The request-handler props (doSendMessageRequest, doUpdateMessageRequest, doDeleteMessageRequest, doMarkReadRequest) are removed. Register handlers with client.config under channel.requestHandlers / thread.requestHandlers.
  • The attachment sizing and Giphy props moved from Channel to Attachment. onMentionsClick / onMentionsHover moved off Channel.
  • useChannelConfig returns the resolved configuration, so fields are renamed, for example typing_events → typingEvents.enabled.

Channel list

  • ChannelList takes a required paginator. All query, event and render props are removed, along with ChannelListUI, usePaginatedChannels and the channel-list utilities.
  • ChannelListContext no longer provides channels, hasNextPage, loadNextPage and setChannels. On ChannelListItem, lastMessage is renamed to previewedMessage, the selection props are removed, and latestMessagePreview / getLatestMessagePreview are removed.
  • Some defaults changed: nothing is selected on mount, channels outside the list's filters are not added, and the list scrolls infinitely.

Threads and headers

  • Thread requires a thread prop and renders its children. Pass message list and composer props to the children you render.
  • ThreadHeader only takes overrideTitle, and closing goes through workspace navigation. ComponentContext.ThreadHeader, HeaderStartContent and HeaderEndContent are removed; headers take StartContent / EndContent instead.
  • ThreadProvider no longer wraps its children in a Channel.

Message lists and messages

  • MessageList no longer accepts messages, hasMore, loadingMoreNewer, jumpToLatestMessage, messageLimit, head or threadList. Use the paginator, the ThreadHead override and useThreadContext() instead.
  • The messageActions prop, MESSAGE_ACTIONS, OPTIONAL_MESSAGE_ACTIONS and getMessageActions() are removed. Pass a filtered defaultMessageActionSet as messageActionSet instead.
  • ComponentContext.Message and the Message prop are replaced by the MessageUI slot.
  • disableDateSeparator is now withDateSeparator with the inverted meaning. noGroupByUser / shouldGroupByUser are now groupByUser. groupStyles is now getGroupStyles and takes a single object.
  • MessageContext no longer has endOfGroup, firstOfGroup, groupedByUser, initialMessage, threadList, mutes or messageIsUnread. Use groupStyles, useIsRenderedAsThreadParent() and useThreadContext() instead.
  • useUserRole is renamed to useMessagePermissions and no longer returns isAdmin, isModerator or isOwner. disableQuotedMessages and PinPermissions are removed.
  • renderText(text, mentionedUsers, options) is now renderText(text, options). Mention handlers receive (event, message).
  • VirtualizedMessageList drops defaultItemHeight, overscan and scrollSeekPlaceHolder. Pass them through additionalVirtuosoProps instead.
  • allowConcurrentAudioPlayback is removed, because playback is always exclusive.

Message composer

  • overrideSubmitHandler, preventClearingOnUnmount, emojiSearchIndex, parent and handleSubmit are removed. For emoji autocomplete, register createTextComposerEmojiMiddleware from stream-chat-react/emojis.
  • useSendMessageFn / useUpdateMessageFn are removed. Use messageComposer.send() / update() instead, and compare the result to 'sent'.
  • A failed send or edit no longer restores the composer.
  • useAttachmentManagerState().hasCustomDoUploadRequest is replaced by customCdn.

Contexts and customization

  • Context hooks no longer take a componentName argument, and required contexts throw when used outside their provider.
  • Slots that the SDK renders without props are typed React.ComponentType without props.

i18n

  • The built-in dictionaries (de, es, fr, hi, it, ja, ko, nl, pt, ru, tr), isLanguageSupported and SupportedTranslations are removed.
  • Translation keys are now namespaced identifiers instead of the English text. A key map is provided for renaming.
  • The Streami18n API has changed: setLanguage returns void and t is read-only.

Data shapes (from stream-chat v10)

  • Custom fields are stored under custom: channel.data.custom.name, user.custom.* and attachment.custom.duration.
  • Server timestamps are TimestampNS (unix nanoseconds), so dayjs(created_at) no longer works on raw values.
  • Message moderation data is in message.moderation.

CSS and markup

  • The Window, str-chat__main-panel and str-chat__container wrappers are removed.
  • The theme scope moved to ChatView. The channel list keeps its own theme scope only when rendered outside ChatView.
  • The str-chat__virtual-message__wrapper--* grouping classes and str-chat__thread--virtualized are removed. Use .str-chat__li--top|middle|bottom|single.

🐛 Notable fixes

  • Message list: keeps the reader's place when older pages load, including on iOS WebKit. The viewport stays still when a jump reaches the latest messages, and the floating date separator no longer stacks on the inline one. The last message stays fully visible in short virtualized lists, and every message that has delivery or read state now shows it.
  • Notifications: pin, mute and delete failures show an error notification. Channel and thread errors render in a stable notification host. Channel and thread list query errors show a retry button.
  • Attachments and gallery: Giphy attachments render in their own group, videos without a thumbnail play, the selected Giphy version loads, and link preview thumbnails fall back to thumb_url.
  • Rendering: markdown is stripped from channel list previews, markdown tables no longer render an empty row, and quotes, locations, polls and the AI stop button use colors that match their bubble.
  • Misc: Pin only shows with the pin-message capability, and the share-location dialog keeps a single position watch. VirtualizedMessageList now passes mention handlers, user handlers and unsafeHTML to messages, and Thread no longer sends requests on mount.

📚 Migration resources

Full changelog: v14.12.0...v15.0.0