This is beta documentation for Stream Chat React SDK v14. For the latest stable version, see the latest version (v13) .

Attachments

Attachment renders the attachments for a message and chooses the UI based on each attachment shape.

Best Practices

  • Keep custom attachment logic focused on the types you actually use.
  • Prefer the supported override points on Attachment instead of customizing low-level attachment containers directly.
  • Combine message.shared_location with message.attachments when you render Attachment inside a fully custom message UI.
  • Use CDN-backed sizing and the SDK sizing handlers for images and videos whenever possible.
  • Treat native giphy messages as their own attachment surface; they render through Giphy, not ModalGallery.
  • Test messages with mixed attachment types so your custom layout still behaves well.

Default Rendering

Attachment groups message attachments before rendering them. The default UI surface is:

Attachment shapeDefault UI
audio attachmentAudio
scraped content / OG attachmentCard
file attachmentFileAttachment
giphy attachmentGiphy
shared locationGeolocation
single image attachmentImage
single video attachmentVideoPlayer
multiple image/video attachmentsModalGallery
voice recording attachmentVoiceRecording
unsupported attachmentUnsupportedAttachment

Attachments with og_scrape_url or title_link are rendered as scraped content cards. Shared location is read from message.shared_location, not from message.attachments.

Native giphy attachments render inline through Giphy. They do not open ModalGallery; the gallery viewer is used for image and mixed image/video gallery content. If you want a modal or fullscreen experience for sent giphies, override Giphy directly.

Basic Usage

The default SDK message UI already renders Attachment for you. If you build your own message component, render it with the current message attachments:

import { Attachment, MessageText, useMessageContext } from "stream-chat-react";

const CustomMessage = () => {
  const { message } = useMessageContext();
  const attachments = [
    ...(message.shared_location ? [message.shared_location] : []),
    ...(message.attachments ?? []),
  ];

  return (
    <div>
      <MessageText />
      {attachments.length ? <Attachment attachments={attachments} /> : null}
    </div>
  );
};

UI Customization

The supported media override points are:

  • Image for a single image attachment
  • Media for a single video attachment
  • ModalGallery for multi-image or mixed image/video galleries

You can also replace AttachmentActions, Audio, Card, File, Geolocation, Giphy, UnsupportedAttachment, and VoiceRecording.

Customizing Attachment inside your own message UI

If you render Attachment directly, pass the custom subcomponents you need:

import {
  Attachment,
  type AttachmentProps,
  type ModalGalleryProps,
  type VideoPlayerProps,
} from "stream-chat-react";

const CustomVideoPlayer = ({ thumbnailUrl, videoUrl }: VideoPlayerProps) => (
  <video controls poster={thumbnailUrl} src={videoUrl} />
);

const CustomModalGallery = ({ items }: ModalGalleryProps) => (
  <div className="custom-gallery-grid">
    {items.map((item, index) => {
      const previewUrl = item.imageUrl ?? item.videoThumbnailUrl;
      if (!previewUrl) return null;

      return (
        <button key={index}>
          <img alt={item.alt ?? "attachment"} src={previewUrl} />
        </button>
      );
    })}
  </div>
);

const CustomAttachment = (props: AttachmentProps) => (
  <Attachment
    {...props}
    Media={CustomVideoPlayer}
    ModalGallery={CustomModalGallery}
  />
);

Replacing the SDK attachment renderer

If you want the SDK Message, VirtualMessage, and thread surfaces to use your attachment renderer, register it with WithComponents:

import {
  Channel,
  MessageInput,
  MessageList,
  WithComponents,
} from "stream-chat-react";

const App = () => (
  <WithComponents overrides={{ Attachment: CustomAttachment }}>
    <Channel>
      <MessageList />
      <MessageInput />
    </Channel>
  </WithComponents>
);

If you customized low-level attachment containers in earlier versions, prefer these v14-supported surfaces first: Attachment, Image, Media, ModalGallery, File, Card, Giphy, Geolocation, VoiceRecording, and AttachmentActions.

Image And Video Sizing

The SDK computes image and video dimensions from CSS and the channel sizing handlers.

Maximum size

Use --str-chat__attachment-max-width to control the maximum width and height used by image and video attachments. The value must resolve to pixels through getComputedStyle, for example 300px, 10rem, or calc(300px - var(--margin)).

If the value does not resolve to a pixel value, attachment sizing can break and message-list scroll behavior can become inaccurate.

File size optimization

The default image and video renderers use the attachment dimensions together with Stream's CDN so the SDK can request a smaller asset when possible.

Aspect ratio

The SDK preserves aspect ratio when it can, but cropping can still happen when:

  1. the message layout forces the attachment to fill the available width
  2. Safari stretches portrait media to the configured max width
  3. the host element's size constraints cannot fit the source without cropping

If you use your own CDN or custom media sizing rules, provide your own imageAttachmentSizeHandler and videoAttachmentSizeHandler on Channel.

Props

PropDescriptionType
actionHandlerAttachment action handler.(dataOrName?: string | FormData, value?: string, event?: React.BaseSyntheticEvent) => Promise<void>
AttachmentActionsComponent used to render attachment actions. Defaults to AttachmentActions.component
attachmentActionsDefaultFocusControls the default focused action per attachment type. Defaults to { giphy: "send" }.AttachmentActionsDefaultFocusByType
attachmentsMessage attachments to render.(Attachment | SharedLocationResponse)[]
AudioComponent used to render audio attachments. Defaults to Audio.component
CardComponent used to render link-preview cards. Defaults to Card.component
FileComponent used to render file attachments. Defaults to FileAttachment.component
GeolocationComponent used to render geolocation attachments. Defaults to Geolocation.component
GiphyComponent used to render giphy attachments. Defaults to Giphy.component
ImageComponent used to render image attachments. Defaults to Image.component
isQuotedRenders the attachment in quoted-message mode.boolean
MediaComponent used to render media attachments. Defaults to VideoPlayer.component
ModalGalleryComponent used to render the attachment gallery modal. Defaults to ModalGallery.component
UnsupportedAttachmentComponent used to render unsupported attachments. Defaults to UnsupportedAttachment.component
VoiceRecordingComponent used to render voice-recording attachments. Defaults to VoiceRecording.component