Info:
This is release candidate documentation for Stream Chat React Native SDK v10. For the latest stable version, see the latest version (v9).

Attachments

A message's attachments render in its bubble, as parts of MessageContent. Message sorts them by kind into the MessageContext values images, videos, files and otherAttachments, and each kind renders in its own part of messageContentOrder: Gallery for images and videos, FileAttachmentGroup for files, and Attachment for each of the others. Every component on this page is an override key of the same name, except UrlPreview, whose default is URLPreview, and FileAttachmentIcon, whose default is FileIcon. Attachments and uploads covers the feature across the layers.

Best practices

  • Render a custom attachment type by overriding Attachment, and hand every other type to the default Attachment, as below. Custom attachments builds a complete one.
  • Replace one kind through its own key, such as FileAttachment or UrlPreview, rather than Attachment as a whole.
  • Change what a tap on an attachment does with onPressMessage on Channel: the payload's emitter says which kind was pressed, and additionalInfo carries the attachment, the thumbnail or the URL. Call defaultHandler() to keep the SDK's behavior.
  • Install a video player, an audio player and a document picker through the native handlers you need. Without a video player, videos render as files; without an audio player, audio attachments do.

Basic usage

A message with an attachment of type product, sent from your backend, renders UnsupportedAttachment by default. This override renders it as a card and hands every other attachment to the default:

src/AttachmentWithProducts.tsx
import { StyleSheet, Text, View } from "react-native";
import {
  Attachment,
  type AttachmentProps,
  WithComponents,
} from "stream-chat-react-native";

const AttachmentWithProducts = (props: AttachmentProps) => {
  const { attachment } = props;

  if (attachment?.type === "product") {
    return (
      <View style={styles.card}>
        <Text style={styles.title}>{attachment.title}</Text>
        {attachment.text ? <Text>{attachment.text}</Text> : null}
      </View>
    );
  }

  return <Attachment {...props} />;
};

const overrides = { Attachment: AttachmentWithProducts };

export const MessagesWithProducts = ({
  children,
}: {
  children: React.ReactNode;
}) => <WithComponents overrides={overrides}>{children}</WithComponents>;

const styles = StyleSheet.create({
  card: { borderRadius: 12, gap: 4, padding: 12, width: 240 },
  title: { fontWeight: "600" },
});

A custom type lands in otherAttachments, which renders only while the message has no file, image or video attachment.

How attachments are sorted

Attachment MessageContext value Renders
an image with an image URL, not a link preview images Gallery
a video, not a link preview, with a video player installed videos Gallery, with VideoThumbnail
a video without a video player files FileAttachment
a file files FileAttachment
audio or a voice recording files AudioAttachment, or FileAttachment without an audio player
an image with og_scrape_url or title_link files UrlPreview, or URLPreviewCompact with urlPreviewType="compact"
Giphy or Imgur otherAttachments Giphy
a link preview of another type otherAttachments UrlPreview or URLPreviewCompact
any other type otherAttachments UnsupportedAttachment

A file, image or video attachment empties otherAttachments, so a message holds either those or the others. An image without an image URL isn't rendered.

Attachment

Renders one attachment by its type, in this order: Giphy for a Giphy or Imgur attachment; URLPreviewCompact or UrlPreview for one with og_scrape_url or title_link; Gallery for an image or a playable video; AudioAttachment for audio or a voice recording, with its upload progress while it uploads; FileAttachment for a file; and UnsupportedAttachment otherwise. FileAttachmentGroup renders each file through the Attachment key too.

Prop Type Default Description
attachment AttachmentType The attachment to render. Without it, nothing renders.
index number Not used, since Attachment doesn't pass it on.
isAttachmentEqual (prevAttachment: AttachmentType, nextAttachment: AttachmentType) => boolean Not used. The component reads it from MessagesContext.
message LocalMessage Not used. The component reads it from MessageContext.
myMessageTheme DeepPartial<Theme> Not used. The component reads it from MessagesContext.
urlPreviewType "compact" | "full" Not used. The component reads it from MessagesContext.

AttachmentType is the Attachment type of stream-chat, imported under another name.

Renders images and videos as a grid of up to four thumbnails, with "+3" over the last one when there are more. Pressing a thumbnail reports the gallery emitter with the thumbnail as additionalInfo; by default it opens the image gallery at that image or video. A prop set here wins over its context value.

Prop Type Default Description
additionalPressableProps Omit<PressableProps, "style"> from MessagesContext Props for each thumbnail's Pressable, applied after its handlers.
alignment Alignment from MessageContext Aligns the grid left or right.
channelId string Not used.
imageGalleryStateStore ImageGalleryStateStore Not used. The component reads it from ImageGalleryContext.
images Attachment[] from MessageContext The images to show.
message LocalMessage from MessageContext The message the image gallery opens with.
messageContentOrder MessageContentType[] from MessageContext With the gallery as the only part and one image or video, the thumbnail's bottom corners are square, so the bubble's corners show.
messageHasOnlyOneMedia boolean Not used. Gallery works it out from messageContentOrder.
myMessageTheme DeepPartial<Theme> from MessagesContext The grid re-renders when it changes.
onLongPress (payload: PressableHandlerPayload) => void from MessageContext Called on a long press on a thumbnail.
onPress (payload: MessagePressableHandlerPayload) => void from MessageContext Called on a press on a thumbnail.
onPressIn ((payload: PressableHandlerPayload) => void) | null from MessageContext Called when a press on a thumbnail starts.
preventPress boolean from MessageContext Turns off presses.
setOverlay React.Dispatch<React.SetStateAction<Overlay>> from OverlayContext Shows the image gallery overlay.
videos Attachment[] from MessageContext The videos to show.

The sizes of the grid come from theme.messageItemView.gallery.

VideoThumbnail

Renders a video's thumbnail with a play icon, inside a Gallery. Without thumb_url it renders only its container.

Prop Type Default Description
imageStyle StyleProp<ImageStyle> Style of the image.
localId string The ID of a pending upload, whose progress the thumbnail shows.
style StyleProp<ViewStyle> Style of the container.
thumb_url string The URL of the thumbnail image.

Giphy

Renders a Giphy or Imgur attachment. A Giphy preview from the /giphy command, which has actions, shows "Only visible to you" and the action buttons, such as Send, Shuffle and Cancel; pressing one calls handleAction. A sent Giphy renders the image, and pressing it reports the giphy emitter. It renders nothing without image_url or thumb_url. A prop set here wins over its context value.

Prop Type Default Description
additionalPressableProps Omit<PressableProps, "style"> from MessagesContext Props for the image's Pressable.
attachment Attachment required The Giphy or Imgur attachment.
giphyVersion keyof Images from MessagesContext The Giphy rendition to show.
handleAction ActionHandler from MessageContext Sends the action of a pressed button.
isMyMessage boolean from MessageContext Picks the background color.
onLongPress (payload: PressableHandlerPayload) => void from MessageContext Called on a long press on the image.
onPress (payload: MessagePressableHandlerPayload) => void from MessageContext Called on a press on the image.
onPressIn ((payload: PressableHandlerPayload) => void) | null from MessageContext Called when a press on the image starts.
preventPress boolean from MessageContext Turns off presses on the image.

GiphyImage renders the image itself, and is exported for a Giphy component of your own.

FileAttachmentGroup

Renders the message's files, each through the Attachment override, in a column.

Prop Type Default Description
files Attachment[] from MessageContext The attachments to render.
message LocalMessage Not used. The component reads it from MessageContext.
styles Partial<{ attachmentContainer: StyleProp<ViewStyle>; container: StyleProp<ViewStyle>; }> Not used, since the component doesn't pass it on. Style the group through theme.messageItemView.fileAttachmentGroup.

FileAttachment

Renders a file through the FilePreview override, with the file's icon and title, and its upload progress while it uploads. Pressing it reports the fileAttachment emitter with the attachment as additionalInfo; by default it opens the file's asset_url. A prop set here wins over its context value.

Prop Type Default Description
additionalPressableProps Omit<PressableProps, "style"> from MessagesContext Props for the Pressable, applied after its handlers.
attachment Attachment required The file.
attachmentIconSize "sm" | "md" | "lg" 'md' The size of the file's icon.
onLongPress (payload: PressableHandlerPayload) => void from MessageContext Called on a long press.
onPress (payload: MessagePressableHandlerPayload) => void from MessageContext Called on a press.
onPressIn ((payload: PressableHandlerPayload) => void) | null from MessageContext Called when a press starts.
preventPress boolean from MessageContext Turns off presses.
styles Partial<{ container: StyleProp<ViewStyle>; details: StyleProp<ViewStyle>; size: StyleProp<TextStyle>; title: StyleProp<TextStyle>; }> the component's own styles Styles passed to FilePreview. A value replaces the defaults as a whole.

FilePreview

Renders the FileAttachmentIcon override for the file's custom.mime_type, the title, and under it indicator, or the size or the duration when there's no indicator. It isn't exported; replace it with the FilePreview key.

Prop Type Default Description
attachment Attachment required The file.
attachmentIconSize "sm" | "md" | "lg" 'md' The size of the icon.
indicator React.ReactNode Rendered in place of the size or duration line. FileAttachment passes its upload progress here.
styles Partial<{ container: StyleProp<ViewStyle>; details: StyleProp<ViewStyle>; size: StyleProp<TextStyle>; title: StyleProp<TextStyle>; }> Styles merged after the theme's.
titleNumberOfLines number 2 The number of lines of the title.

FileIcon

Renders the icon for a MIME type, from the icons override map: PDF, DOC, SpreadSheet, Presentation, ZIP, Audio, Video, Code, or OtherFileIcon for any other type. It's the default of the FileAttachmentIcon key.

Prop Type Default Description
mimeType string The file's MIME type.
size "sm" | "md" | "lg" 'md' 'sm' is 19 by 24 points, 'md' 32 by 40, 'lg' 40 by 48.

AudioAttachment

Plays an audio attachment or a voice recording: a play button, the remaining time, a waveform for a voice recording with waveform_data or a progress bar otherwise, which the user can drag to seek, and a speed button. Each message's attachment has its own player; Voice recordings and audio playback explains how players are shared and when they stop. In a message, Attachment renders it with showTitle={false} and showSpeedSettings.

Prop Type Default Description
containerStyle StyleProp<ViewStyle> Style of the container.
hideProgressBar boolean false Hides the waveform or progress bar.
indicator React.ReactNode Rendered in place of the time and progress, and hides the speed button. Attachment passes the upload progress while the file uploads.
isPreview boolean false Set when the attachment shows in the composer. The player is released when the preview unmounts.
item AudioAttachmentType required The attachment, with an id and type: 'audio' | 'voiceRecording'.
message LocalMessage The message, which identifies the attachment's player.
showSpeedSettings boolean false Shows the playback speed button.
showTitle boolean true Shows the title, or "Voice Message" for a voice recording.
styles { container?: StyleProp<ViewStyle>; playPauseButton?: StyleProp<ViewStyle>; speedSettingsButton?: StyleProp<ViewStyle>; durationText?: StyleProp<TextStyle>; leftContainer?: StyleProp<TextStyle>; } Styles of the parts.
testID string The container's testID.

URLPreview and URLPreviewCompact

URLPreview, the default of the UrlPreview key, renders a link preview as a card: the image, with a play icon for a video link, the title, the description and the URL. URLPreviewCompact renders the same in a smaller layout, and urlPreviewType="compact" on Channel picks it. Pressing either reports the urlPreview emitter with the URL as additionalInfo; by default it opens og_scrape_url. Both remount when the message updates. Link previews covers the feature.

Prop Type Default Description
additionalPressableProps Omit<PressableProps, "style"> from MessagesContext Props for the card's Pressable, applied after its handlers.
attachment Attachment required The link preview.
channelId string Not used.
ImageComponent React.ComponentType<ImageProps> the ImageComponent override Renders the image.
isAttachmentEqual (prevAttachment: Attachment, nextAttachment: Attachment) => boolean from MessagesContext When set, decides whether the card re-renders once the SDK's own check finds the attachment unchanged.
messageId string Not used.
myMessageTheme DeepPartial<Theme> from MessagesContext The card re-renders when it changes.
onLongPress (payload: PressableHandlerPayload) => void from MessageContext Called on a long press.
onPress (payload: MessagePressableHandlerPayload) => void from MessageContext Called on a press.
onPressIn ((payload: PressableHandlerPayload) => void) | null from MessageContext Called when a press starts.
preventPress boolean from MessageContext Turns off presses.
styles Partial<{ cardCover: StyleProp<ImageStyle>; cardFooter: StyleProp<ViewStyle>; container: StyleProp<ViewStyle>; description: StyleProp<TextStyle>; linkPreview: StyleProp<ViewStyle>; linkPreviewText: StyleProp<TextStyle>; title: StyleProp<TextStyle>; }> Styles of the parts.

URLPreviewCompact takes the same props without isAttachmentEqual:

Prop Type Default Description
additionalPressableProps Omit<PressableProps, "style"> from MessagesContext Props for the card's Pressable, applied after its handlers.
attachment Attachment required The link preview.
channelId string Not used.
ImageComponent React.ComponentType<ImageProps> the ImageComponent override Renders the image.
messageId string Not used.
myMessageTheme DeepPartial<Theme> from MessagesContext The card re-renders when it changes.
onLongPress (payload: PressableHandlerPayload) => void from MessageContext Called on a long press.
onPress (payload: MessagePressableHandlerPayload) => void from MessageContext Called on a press.
onPressIn ((payload: PressableHandlerPayload) => void) | null from MessageContext Called when a press starts.
preventPress boolean from MessageContext Turns off presses.
styles Partial<{ cardCover: StyleProp<ImageStyle>; cardFooter: StyleProp<ViewStyle>; container: StyleProp<ViewStyle>; description: StyleProp<TextStyle>; linkPreview: StyleProp<ViewStyle>; linkPreviewText: StyleProp<TextStyle>; title: StyleProp<TextStyle>; }> Styles of the parts.

UnsupportedAttachment

Renders an attachment of a type the SDK doesn't know: the FileAttachmentIcon override for its custom.mime_type, and its title, or "Unsupported Attachment". It isn't exported; replace it with the UnsupportedAttachment key, or render your type from an Attachment override as above.

Prop Type Default Description
attachment Attachment required The attachment.
attachmentIconSize "sm" | "md" | "lg" 'md' The size of the icon.
isMyMessage boolean Not used. The component reads it from MessageContext.
  • useMessageContext() returns the message's attachments by kind: images, videos, files and otherAttachments.
  • useAudioPlayer() returns the player of an audio attachment, for a player of your own. See Voice recordings and audio playback.
  • buildGallery() computes the grid Gallery lays out.