# Overlays and bottom sheets

> **Info:** This is release candidate documentation for **Stream Chat React Native SDK v10**. For the latest stable version, see the [latest version (v9)](https://getstream.io/chat/docs/sdk/react-native/).

Some of the SDK's UI opens on top of the screen: the message menu on a long press, the image gallery, the attachment picker, the list of who reacted, the poll screens. Each opens in one of these ways:

| Kind                  | What opens this way                                                                                                          | Drawn by                                     |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
| The message overlay   | the message menu                                                                                                             | `OverlayProvider`, above your screens        |
| The gallery overlay   | the image gallery                                                                                                            | `OverlayProvider`, above your screens        |
| Bottom sheets         | who reacted, more reactions, commands, the gallery's grid, a channel's options, a member's actions, the channel image picker | `BottomSheetModal`, in a native modal window |
| The attachment picker | the photo grid and the picker's sources                                                                                      | `Channel` and `Thread`, below the composer   |
| Full-screen modals    | polls' results, options and comments, poll creation, channel details' member list, media, files, pinned messages, editing    | a native modal window                        |

The two overlays need `OverlayProvider` above the screen. The rest need nothing more than the `Channel`, `Thread` or `ChannelDetails` they belong to.

## OverlayProvider

`OverlayProvider` goes around your navigation, above `Chat`, as in the [Quick start](https://getstream.io/chat/docs/sdk/react-native/v10/getting-started/quick-start/). It renders your app, then on top of it a layer for the message menu and, while it's open, the image gallery. Its layer covers the whole window, so it draws above your navigation's headers and tab bars.

| Prop                              | What it does                                                                                                                                  |
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `value.style`                     | the theme of the overlays and everything else below `OverlayProvider`. See [Theming](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/theming/) |
| `i18nInstance`                    | the `Streami18n` instance for the overlays' text. Pass the one you give `Chat`                                                                |
| `accessibility`                   | the opt-in accessibility layer. See [Accessibility](https://getstream.io/chat/docs/sdk/react-native/v10/features/app-experience/accessibility/)                   |
| `autoPlayVideo`                   | whether a video in the gallery starts playing when it opens                                                                                   |
| `giphyVersion`                    | which rendition of a Giphy the gallery shows                                                                                                  |
| `numberOfImageGalleryGridColumns` | the number of columns of the gallery's grid                                                                                                   |

`OverlayProvider` draws in the window it's mounted in. A screen in another native window, such as a React Native `Modal` or a native modal presentation on iOS, needs an `OverlayProvider` of its own inside it, or the message menu opens behind the modal. See [Chat in modals](https://getstream.io/chat/docs/sdk/react-native/v10/ui/layout/chat-in-modals/).

## The message menu

A long press on a message opens its menu. A press on a message that failed to send opens it too, so the user can retry or delete it.

1. The keyboard closes. On a long press, the device gives a haptic tap.
2. The SDK measures where the message is on screen, and the overlay dims the screen behind it.
3. The message itself moves into the overlay, in place.
4. The reaction picker shows above the message, and the action list below it.

The menu doesn't open for a blocked message, for a message whose attachment has actions of its own, such as a Giphy preview the user is still choosing, or when `onLongPressMessage` on `Channel` replaces the long press. A long press on a message the server bounced asks the user to send it anyway, edit it or delete it instead.

The menu closes when the user picks an action or a reaction, taps the dimmed background, presses the Android back button, or rotates the device. When the message and the menu are taller than the screen, the user scrolls them by dragging.

What's in the menu:

| Part                                              | Override key                                                    | Shown when                                  |
| ------------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------- |
| The reaction picker, with a button for more emoji | `MessageReactionPicker`                                         | the user has `send-reaction` in the channel |
| The action list                                   | `MessageActionList`, with `MessageActionListItem` for each item | there are actions for the message           |
| The dimmed background                             | `MessageOverlayBackground`                                      | always                                      |

The actions in the list, and how to change them, are on [Actions](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/actions/#message-actions). The picker's reactions are the `isMain` entries of `supportedReactions` on `Channel`; the more-emoji button opens a bottom sheet with the SDK's full emoji set, whatever `supportedReactions` holds. See [Reactions](https://getstream.io/chat/docs/sdk/react-native/v10/features/messaging/reactions/).

`MessageOverlayBackground` is read by `OverlayProvider`, so set it in a `WithComponents` around `OverlayProvider`. The picker and the action list render inside the message, so they take the overrides that reach the message.

The optional `MessageActions` key replaces the layout of the whole overlay. It receives the animated styles the default layout positions its parts with, `hostStyle`, `topItemStyle`, `bottomItemStyle` and `portalHostStyle`, and renders the portal hosts that the message, the picker and the action list move into. It's for a menu with a different arrangement; to change what's in the menu, override the parts above.

### Fixed UI above a closing menu

When the menu closes, the message animates back into the list. A part of the screen that should stay drawn above it, such as a header inside the screen, goes in a `PortalWhileClosingView`: while the menu closes, it moves its children into the overlay above the message, and keeps their space in the layout. The SDK wraps the composer and the suggestion list this way. The [Channel UI](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/channel-ui/#the-channel-header) page shows it around a header.

## The image gallery

Pressing an image or a video in a message opens the gallery on that item, with the message's other images and videos to swipe through.

| Part                                                        | Override key                |
| ----------------------------------------------------------- | --------------------------- |
| The header: the back button, the sender and the time        | `ImageGalleryHeader`        |
| The footer: the share button, the position, the grid button | `ImageGalleryFooter`        |
| The video controls in the footer                            | `ImageGalleryVideoControls` |
| The grid of every item, in a bottom sheet                   | `ImageGalleryGrid`          |

A tap hides and shows the header and footer. Pinching or a double tap zooms, and a swipe down closes the gallery, as do the back button in the header and the Android back button. The share button shows only when the share and file-system handlers are registered, which depends on the optional packages your app installs: see [Installation](https://getstream.io/chat/docs/sdk/react-native/v10/getting-started/installation/).

The gallery is rendered by `OverlayProvider`, so these keys, and the icons the gallery uses, take effect only from a `WithComponents` around `OverlayProvider`. Its time format is the `timestamp.ImageGalleryHeader` translation key: see [Localization](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/localization/#date-and-time-formatting).

## Bottom sheets

The SDK's bottom sheets are `BottomSheetModal`s. Each one is a React Native `Modal`, its own native window, so it opens above everything, the overlays and your navigation included, and needs no provider:

| Sheet               | Opens from                                               | Content key                                                                              |
| ------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| Who reacted         | a press on a message's reactions                         | `MessageUserReactions`, with `MessageUserReactionsItem` and `MessageUserReactionsAvatar` |
| More reactions      | the more-emoji button of the reaction picker             | none                                                                                     |
| Commands            | the commands button of the attachment picker             | none                                                                                     |
| The gallery's grid  | the grid button of the gallery                           | `ImageGalleryGrid`                                                                       |
| A channel's options | the options button of a channel-list row's swipe actions | `ChannelDetailsBottomSheet`, with `ChannelDetailsHeader`                                 |
| A member's actions  | a member in channel details                              | `ChannelMemberActionsSheet`                                                              |
| The channel image   | editing the channel in channel details                   | `ChannelEditImageSheet`                                                                  |

A sheet closes when the user drags it down, taps the backdrop, or presses the Android back button. A sheet shorter than the screen can be dragged up to full height. On iOS, the sheet moves up above the keyboard while it's open.

`BottomSheetModal` is exported, so your own sheets can match the SDK's:

```tsx
import { useState } from "react";
import { Pressable, StyleSheet, Text, View } from "react-native";
import { BottomSheetModal } from "stream-chat-react-native";

export const ChannelRulesButton = ({ rules }: { rules: string }) => {
  const [visible, setVisible] = useState(false);

  return (
    <>
      <Pressable accessibilityRole="button" onPress={() => setVisible(true)}>
        <Text>Rules</Text>
      </Pressable>
      <BottomSheetModal
        enableDynamicSizing
        onClose={() => setVisible(false)}
        visible={visible}
      >
        <View style={styles.content}>
          <Text>{rules}</Text>
        </View>
      </BottomSheetModal>
    </>
  );
};

const styles = StyleSheet.create({
  content: { padding: 16 },
});
```

| Prop                  | Default         | What it does                                                          |
| --------------------- | --------------- | --------------------------------------------------------------------- |
| `visible`             |                 | whether the sheet is open. While it's `false`, nothing renders        |
| `onClose`             |                 | called when the user closes the sheet. Set `visible` to `false` in it |
| `height`              | half the window | the sheet's height, capped to the window                              |
| `enableDynamicSizing` | `false`         | sizes the sheet to its content, up to `height`                        |
| `lazy`                | `false`         | renders the content after the opening animation                       |

It reads the theme, so render it below `OverlayProvider` or `Chat`. Its look is the theme's `bottomSheetModal` key: `container`, `contentContainer`, `handle`, `overlay` and `wrapper`.

## The attachment picker

The attachment picker is a bottom sheet that `Channel` and `Thread` render below their children. The composer's attach button opens it. Unlike the sheets above, it isn't a separate window: it slides up inside the channel's screen, under the composer, and the screen's content stays above it. Opening the keyboard closes it, and so does the Android back button.

Its parts are `AttachmentPickerSelectionBar`, the row of sources, `AttachmentPickerContent`, what the selected source shows, and `ImageOverlaySelectedComponent`, the mark on a selected photo. Its sources and props are on [Message composer UI](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-composer-ui/#the-attachment-picker).

## Full-screen modals

The poll screens and the screens channel details opens are React Native `Modal`s too. On iOS, most are presented as a page sheet, and the media, files and pinned messages screens of channel details as full screen; on Android, all are full screen. They close on the Android back button.

| Screen                                            | Content key                                                              |
| ------------------------------------------------- | ------------------------------------------------------------------------ |
| A poll's results                                  | `PollResultsContent`, and `PollOptionFullResultsContent` for one option  |
| A poll's options                                  | `PollAllOptionsContent`                                                  |
| A poll's comments                                 | `PollAnswersListContent`                                                 |
| Creating a poll                                   | `CreatePollContent`, which has no default and replaces the built-in form |
| Channel details' member list                      | `ChannelMemberList`                                                      |
| Channel details' media, files and pinned messages | `MediaList`, `FileAttachmentList`, `PinnedMessageList`                   |
| Editing a channel, adding members                 | `ChannelEditDetailsForm`, `ChannelAddMembersForm`                        |

A dialog that only asks for text, such as suggesting a poll option or adding a comment, is a small `Modal` of its own. Confirmations, such as deleting a message or leaving a channel, use the platform's `Alert`.

## Back button handling

On Android, the back button closes what's on top before your navigation sees it:

| Open                                          | The back button                                   |
| --------------------------------------------- | ------------------------------------------------- |
| the message menu                              | closes it                                         |
| the image gallery                             | closes it                                         |
| a bottom sheet or a full-screen modal         | closes it, through the `Modal`'s `onRequestClose` |
| the attachment picker, with a source selected | closes it                                         |
| nothing                                       | goes to your navigation                           |

The overlays and the picker register their `BackHandler` listeners while they're mounted and return `true` only while they have something open, so your own listeners keep working the rest of the time.

## Pitfalls

- **`OverlayProvider` inside a screen.** Its overlays then cover only that screen, under the navigation's header. Put it around the navigation container's content, once.
- **A chat screen in a native modal.** The message menu opens in the window behind it. Give the modal its own `OverlayProvider`.
- **Gallery or overlay overrides below `OverlayProvider`.** `OverlayProvider` never sees them. Put that `WithComponents` above it.
- **A header that the closing message animates over.** Wrap it in `PortalWhileClosingView`.
- **Expecting the attachment picker over the whole screen.** It belongs to the `Channel`'s screen and opens under the composer, not in its own window.

Used in: [Message actions](https://getstream.io/chat/docs/sdk/react-native/v10/features/messaging/message-actions/), [Reactions](https://getstream.io/chat/docs/sdk/react-native/v10/features/messaging/reactions/), [Attachments and uploads](https://getstream.io/chat/docs/sdk/react-native/v10/features/rich-content/attachments-and-uploads/) and [Chat in modals](https://getstream.io/chat/docs/sdk/react-native/v10/ui/layout/chat-in-modals/).

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/overlays-and-bottom-sheets/](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/overlays-and-bottom-sheets/).