Attachments

Attachment renders a list of message attachments and chooses the UI based on attachment type. The table below shows which UI component is used:

Attachment TypeUI ComponentFile type(s) (non-exhaustive)
audioAudioMP3, WAV, M4A, FLAC, AAC
fileFileDOC, DOCX, PDF, PPT, PPTX, TXT, XLS, XLSX
galleryGallerywhen a message has more than 1 'image' type attachment
imageImageHEIC, GIF, JPEG, JPG, PNG, TIFF, BMP
videoReactPlayerMP4, OGG, WEBM, Quicktime(QTFF, QT, or MOV)
voiceRecordingVoiceRecordingMP3, WAV
geolocationGeolocationNot applicable

Best Practices

  • Combine message.shared_location with message.attachments when rendering.
  • Use component overrides only for the attachment types you customize.
  • Keep image/video sizing within pixel-computable CSS values.
  • Prefer CDN-based resizing for performance and bandwidth savings.
  • Test attachments with mixed content to verify layout and cropping.

Attachments that don’t match the types above are treated as scraped content and should include og_scrape_url or title_link to render with Card. Otherwise they won’t render.

geolocation is a special case: the data comes from message.shared_location, not message.attachments.

Basic Usage

By default, Attachment is included in MessageSimple. For a custom Message UI component, import Attachment and render it conditionally when attachments exist.

const CustomMessage = () => {
  // consume `MessageContext`
  const { message } = useMessageContext();

  const finalAttachments = useMemo(
    () =>
      !message.shared_location && !message.attachments
        ? []
        : !message.shared_location
          ? message.attachments
          : [message.shared_location, ...(message.attachments ?? [])],
    [message],
  );

  return (
    <div>
      {finalAttachments.length > 0 && (
        <Attachment attachments={finalAttachments} />
      )}
      // render remaining custom Message UI component
    </div>
  );
};

<Chat client={client}>
  <Channel channel={channel} Message={CustomMessage}>
    <MessageList />
    <MessageInput />
  </Channel>
</Chat>;

UI Customization

Attachment accepts component overrides for each attachment type. Building on the example above, here’s how to customize a single attachment renderer:

const CustomImage = (props) => {
  // render custom image component here
};

const CustomMessage = () => {
  // consume `MessageContext`
  const { message } = useMessageContext();

  const finalAttachments = useMemo(
    () =>
      !message.shared_location && !message.attachments
        ? []
        : !message.shared_location
          ? message.attachments
          : [message.shared_location, ...(message.attachments ?? [])],
    [message],
  );

  return (
    <div>
      {finalAttachments.length > 0 && (
        <Attachment attachments={message.attachments} Image={CustomImage} />
      )}
      {/* render remaining custom Message UI component */}
    </div>
  );
};

<Chat client={client}>
  <Channel channel={channel} Message={CustomMessage}>
    <MessageList />
    <MessageInput />
  </Channel>
</Chat>;

Or wrap Attachment directly:

const CustomAudioAttachment = (props) => {
  // you can add any custom data (such as "customType" in this case)
  if (props.og?.customType === "voice-memo")
    return <div>my custom voice-memo component</div>;
  return <Audio {...props} />;
};

const CustomAttachment = (props) => {
  return <Attachment {...props} Audio={CustomAudioAttachment} />;
};

<Chat client={client}>
  <Channel channel={channel} Attachment={CustomAttachment}>
    <MessageList />
    <MessageInput />
  </Channel>
</Chat>;

Image and video sizing

The following section describes how image and video sizes are computed.

Maximum size

You can control the maximum width and height of images and videos with the --str-chat__attachment-max-width CSS variable. The value of this variable must be a value that can be computed to a valid pixel value using the getComputedStyle method (for example: 300px, 10rem, calc(300px - var(--margin)), but not 100%). If you provide an invalid value, the image and video sizing can break, which can lead to scrolling issues inside the message list (for example the message list isn't scrolled to the bottom when you open a channel).

If you set an invalid value to the variable, you'll see a warning on the browser's console:

AttachmentSizeWarning

File size optimization

Based on the CSS settings provided for images and videos (see Maximum size section), the SDK will load an image (or thumbnail image in case of a video file) with a reduced file size while still providing sufficient image quality for the given dimensions. This will result in less network traffic and faster image load for users.

For example, if an image’s max size is 300px and the original is 965 × 1280, the SDK loads a smaller version via Stream’s CDN.

Aspect ratio

The SDK tries to preserve original aspect ratio, but there are exceptions where cropping occurs:

  1. If a message has multiple text lines and/or multiple attachments, the image/video can stretch to max-width.

Example 1 - message with one line of text - image is displayed with original aspect ratio

ImageSizing1

Example 2 - message with multiple lines of text - image is cropped

ImageSizing2

  1. In Safari, portrait images/videos are stretched to max-width.

Example 3 - portrait images in Safari - image is cropped

ImageSizing3

  1. If the image/video can’t fit the host element’s max-width/max-height constraints without cropping.

File size optimization and maintaining aspect ratio uses features provided by Stream's CDN. If you're using your own CDN you'll likely have to provide your own implementation for this. You can do this using the imageAttachmentSizeHandler and videoAttachmentSizeHandler props.

If you plan to override attachment sizing with custom CSS, note:

The sizing logic for images/videos (via imageAttachmentSizeHandler and videoAttachmentSizeHandler) requires host elements (usually img and video) to have max-height/height and max-width values that resolve to pixels via getComputedStyle. See Maximum size.

Props

attachments

The message attachments to render, see Attachment Format in the general JavaScript docs.

Type
array

actionHandler

The handler function to call when an action is performed on an attachment, examples include canceling a /giphy command or shuffling the results.

Type
(dataOrName?: string | FormData, value?: string, event?: React.BaseSyntheticEvent) => Promise<void>

AttachmentActions

Custom UI component for displaying attachment actions.

TypeDefault
componentAttachmentActions

Audio

Custom UI component for displaying an audio type attachment.

TypeDefault
componentAudio

Card

Custom UI component for displaying a card type attachment.

TypeDefault
componentCard

File

Custom UI component for displaying a file type attachment.

TypeDefault
componentFile

Custom UI component for displaying a gallery of image type attachments.

TypeDefault
componentGallery

Geolocation

Custom UI component for displaying geolocation data.

TypeDefault
componentGeolocation

Image

Custom UI component for displaying an image type attachment.

TypeDefault
componentImage

Media

Custom UI component for displaying a video type attachment, defaults to use the react-player dependency.

TypeDefault
componentReactPlayer