Attachment Selector
AttachmentSelector is the button before the composer's input. It opens a menu to upload a file, create a poll, share a location or pick a command. The menu is an action set: a list of actions, each with a type and a component. Attachments and uploads explains uploads, and Actions explains the action set.
Best practices
- Change the menu by passing your own
attachmentSelectorActionSet, built fromdefaultAttachmentSelectorActionSet. Register the selector that renders it under theAttachmentSelectorkey. - Decide who can upload, create polls and share locations on the server and in
client.config. The selector shows only what the user can do, and that filter can't be turned off. - Give a custom action a
typeof its own. The four built-in types are filtered, whatever component you give them. - Set
getModalPortalDestinationwhen the selector renders outside aChannel, or when the channel's container clips its dialogs.
Default behavior
The default menu has four actions, in this order:
| Type | Label | What it does | Shown when |
|---|---|---|---|
uploadFile |
File | Opens the file picker | Uploads are allowed and the message has room for another file |
createPoll |
Poll | Opens the poll creation dialog | Polls are turned on, the user has the send-poll capability, and it's not a thread |
addLocation |
Location | Opens the location sharing dialog | Location sharing is turned on, and it's not a thread |
selectCommand |
Commands | Opens a submenu of the channel's commands | The channel type has commands |
AttachmentSelector applies this filter itself, every time it renders, to the default set and to any set you pass. An action of any other type is always shown.
What the selector renders depends on what's left:
- No actions: nothing.
- Only
uploadFile:SimpleAttachmentSelector, a button that opens the file picker directly. It renders only when the user has theupload-filecapability, even whenattachments.customCdnistrue. So with a custom CDN and noupload-file, a user who can only upload sees no button at all. - Otherwise: the button and its menu.
The button is disabled during a slow-mode cooldown. While a command is selected, it's hidden with a CSS transition and taken out of the tab order. Inside a message, as when a message is edited where it sits, the default layout renders SimpleAttachmentSelector in its place, which checks only the upload-file capability.
Enabling features
Each action follows the settings below. Configuration explains how the server and client.config combine.
- File:
attachments.enabledin the composer configuration, the channel type'suploadssetting and the user'supload-filecapability. Withattachments.customCdn: true, onlyattachments.enabledcounts. The action also disappears when the message holdsattachments.maxNumberOfFilesPerMessagefiles. See Attachments and uploads. - Poll:
polls.enabledin the composer configuration, the channel type'spollssetting and thesend-pollcapability. See Polls. - Location:
location.enabledin the composer configuration and the channel type'sshared_locationssetting. See Location sharing. - Commands: the channel type's
commands. See Commands and Giphy.
Custom action sets
AttachmentSelector props:
| Prop | Type | Default | Description |
|---|---|---|---|
attachmentSelectorActionSet |
AttachmentSelectorAction[] |
defaultAttachmentSelectorActionSet |
The actions of the menu, top to bottom. The filter in Default behavior still applies. |
buttonProps |
Omit<ButtonProps, "onClick"> |
none | Props for the button that opens the menu, or for the button of SimpleAttachmentSelector. |
getModalPortalDestination |
() => HTMLElement | null |
the Channel container |
The element the action dialogs render into. See Custom modal portal destination. |
An AttachmentSelectorAction has these fields:
| Field | Type | Description |
|---|---|---|
type |
"uploadFile" | "createPoll" | "addLocation" | "selectCommand" | string |
What the action is. Also the key passed to openModalForAction. |
ActionButton |
ComponentType<AttachmentSelectorActionProps> |
The menu item. It gets openModalForAction(type), and submenuItems and submenuHeader when the action has a submenu. |
ModalContent |
ComponentType<AttachmentSelectorModalContentProps> |
What openModalForAction(type) opens in a modal. It gets close. |
Submenu |
ContextMenuSubmenu |
A submenu, as the commands action has. |
Header |
ContextMenuHeaderComponent |
The header of the submenu. |
id |
string |
An identifier of your own. The selector doesn't read it. |
A menu item closes the menu with closeMenu() from useContextMenuContext(). The default items are exported as DefaultAttachmentSelectorComponents: File, Poll, Location and Command.
This selector leaves out Location:
import type { PropsWithChildren } from "react";
import {
AttachmentSelector,
defaultAttachmentSelectorActionSet,
WithComponents,
} from "stream-chat-react";
const actionSet = defaultAttachmentSelectorActionSet.filter(
({ type }) => type !== "addLocation",
);
const AttachmentSelectorWithoutLocation = () => (
<AttachmentSelector attachmentSelectorActionSet={actionSet} />
);
const overrides = { AttachmentSelector: AttachmentSelectorWithoutLocation };
export const WithoutLocationAction = ({ children }: PropsWithChildren) => (
<WithComponents overrides={overrides}>{children}</WithComponents>
);Attachment selector actions adds an action of its own, and the Attachment actions recipe builds one with a dialog.
Poll and location dialogs
The createPoll and addLocation actions open the PollCreationDialog and ShareLocationDialog overrides, unless the action has a ModalContent of its own. Both dialogs get close. Opening the poll dialog starts a new poll in the composer's pollComposer.
import type { PropsWithChildren } from "react";
import type { PollCreationDialogProps } from "stream-chat-react";
import { PollCreationDialog, WithComponents } from "stream-chat-react";
const PollDialogWithIntro = (props: PollCreationDialogProps) => (
<div className="poll-dialog">
<p>Polls close after a week.</p>
<PollCreationDialog {...props} />
</div>
);
const overrides = { PollCreationDialog: PollDialogWithIntro };
export const WithPollDialogIntro = ({ children }: PropsWithChildren) => (
<WithComponents overrides={overrides}>{children}</WithComponents>
);The dialogs' own props are on Poll components and Location sharing.
Custom modal portal destination
The action dialogs render into the Channel container, the element with the str-chat__channel id. Outside a Channel, or when that container clips them, pass getModalPortalDestination:
import { AttachmentSelector } from "stream-chat-react";
const getModalPortalDestination = () =>
document.getElementById("chat-modal-root");
export const AttachmentSelectorWithModalRoot = () => (
<AttachmentSelector getModalPortalDestination={getModalPortalDestination} />
);Register it under the AttachmentSelector key. Dialogs explains modals.
AttachmentSelectorContext
The menu items of AttachmentSelector can read AttachmentSelectorContext with useAttachmentSelectorContext():
| Value | Type | Description |
|---|---|---|
fileInput |
HTMLInputElement | null |
The hidden file input of the selector. Call fileInput.click() to open the file picker. null until the input renders, and outside the selector. |
SimpleAttachmentSelector doesn't provide this context.
Hooks
useAttachmentManagerState: whether uploads, polls and locations are turned on, and how many files still fit.useCanCreatePoll: whether the poll being composed can be sent.useMessageComposerCommands: the channel's commands, as the commands submenu shows them.useChannelCapabilities: the user's capabilities, such asupload-fileandsend-poll.