Mentions
What users get
Typing @ in the composer suggests people and groups to mention. The sent message highlights each mention, and the server notifies the people it names.
- Suggestions.
@opens a list of channel members,@channel,@here, roles and user groups, narrowed as the user types. The local member search ignores common accents such as é and ü by default, so "rene" finds "René". - Inserting. Picking a suggestion inserts it into the text, for example
@Ben. Deleting that text removes the mention. - Highlighting. Mentions in sent messages are styled, and can be clicked or hovered.

There are five kinds of mention. The kinds other than user need a capability in the channel:
| Kind | Typed as | Notifies | Capability | Permission in the dashboard |
|---|---|---|---|---|
user |
@<name> |
one user | none | none |
channel |
@channel |
everyone in the channel | notify-channel |
NotifyChannel |
here |
@here |
members who are online | notify-here |
NotifyHere |
role |
@<role> |
users with that role | notify-role |
NotifyRole |
user_group |
@<group> |
members of a user group | notify-group |
NotifyGroup |
The message field each kind is sent in is listed in Kinds of mentions. A received message lists its user groups in mentioned_groups.
How it works across the layers
State: the text composer
The user types "Thanks @be" in "Design":
- The text composer runs its middleware on every change. The mentions middleware finds the
@bebefore the cursor and asksMentionsSearchSourcefor suggestions. - The search source collects users,
@channeland@here, roles and user groups that match "be". It offers only the kinds the user has the capability for. Where the suggestions come from explains each search. - The suggestions land in the text composer's state as
suggestions, and the UI lists them. - The user picks Ben. The middleware replaces
@bewith@Benand adds Ben to the text composer'smentions. - When they send, the composer sends each mention that is still in the text with the message.
The middleware and the search source are explained on Mentions.
UI: suggestions and highlighting
The input, TextareaComposer, renders the suggestion list while the text composer has suggestions:
AutocompleteSuggestionList, by defaultSuggestionList, lists them and handles the keyboard.- Each row is an
AutocompleteSuggestionItem. For@, the row rendersMentionItem, which picksUserItem,BroadcastMentionItem(@channeland@here),RoleItemorUserGroupItem.
In the message list, the message text is rendered by renderText, which turns each mention into a Mention element:
<span
class="str-chat__message-mention"
data-mention-type="user | channel | here | role | user_group"
data-mention-id="<the mentioned entity's id>"
data-user-id="<the user's id, for user mentions only>"
>
@Ben
</span><MessageList/> takes onMentionsClick and onMentionsHover. They run when the user clicks or hovers the text of a message that has mentions. With onMentionsClick, each @name in the text gets cursor: pointer, and the message text can be reached with Tab: pressing Enter or Space on it calls the handler, as a click does. Without it, mentions are highlighted but not clickable. Reacting to clicks and hovers shows a handler. See The input for the composer side.
Turning it on or off
User mentions are always available. Grant the capabilities in the table under What users get in the Stream Dashboard under Chat Messaging → Roles & Permissions: pick the role (for example channel_member) and the channel type (for example messaging), then turn on the permissions. Until the user has a capability, that kind doesn't appear in the suggestions.
Two kinds also need data on the server:
- Roles are the roles defined on the same Roles & Permissions page.
- User groups are named sets of users, mentioned as one with
@<group name>. They don't depend on channel membership: a group can be mentioned in any channel where group mentions are allowed. Create and manage them with a server-side SDK; see the User Groups API reference.
Customizing
Changing the search
To change what is searched, for example to suggest every user of the app or to change the page size, give the mentions middleware a MentionsSearchSource of your own; see Customizing mention search for the options and a sample.
Its transliterate option also lets names written in other scripts match what the user types. Pass a function that returns the text in Latin script, such as the default export of @sindresorhus/transliterate, and typing "@ana" suggests "Анатолий". It applies only to names compared locally; queries to the server aren't transliterated.

The search source is replaced in a messageComposer setup function. There is one setup function per kind, so do all composer setup in one; see Setup functions.
Replacing a suggestion row
Pass your own row components to MentionItem, and give the list the new @ row through SuggestionList's suggestionItemComponents:
import type { MentionSuggestion } from "stream-chat";
import type {
SuggestionListItemComponentProps,
SuggestionListProps,
UserItemProps,
} from "stream-chat-react";
import {
defaultComponents,
MentionItem,
SuggestionList,
UserItem,
WithComponents,
} from "stream-chat-react";
const UserRow = (props: UserItemProps) => (
<UserItem {...props} className="user-row" />
);
const MentionRow = (props: SuggestionListItemComponentProps) => (
<MentionItem
{...props}
entity={props.entity as MentionSuggestion}
UserItem={UserRow}
/>
);
const Suggestions = (props: SuggestionListProps) => (
<SuggestionList
{...props}
suggestionItemComponents={{ ...defaultComponents, "@": MentionRow }}
/>
);
export const App = () => (
<WithComponents overrides={{ AutocompleteSuggestionList: Suggestions }}>
{/* the rest of the app */}
</WithComponents>
);MentionItem also takes BroadcastMentionItem, RoleItem and UserGroupItem, and SpecialMentionItem for any other kind. The Custom suggestions recipe builds complete rows.
Styling mentions
Each mention has data-mention-type, so CSS can style the kinds differently:
.str-chat__message-mention[data-mention-type="channel"],
.str-chat__message-mention[data-mention-type="here"] {
color: var(--str-chat__accent-error);
}To render mentions with your own markup, for example as links to profiles, pass a mention component to renderText; see Custom element rendering.
Reacting to clicks and hovers
To do something when the user clicks a mention, such as opening the user's profile, pass onMentionsClick to <MessageList/>, <VirtualizedMessageList/> or <Message/>. onMentionsHover does the same for hovers. Both are called with (event, message).
The handler doesn't say which mention was clicked: it runs for a click anywhere in the message text. Find the mention from the clicked element:
- Look up the nearest
.str-chat__message-mentionfromevent.target. Without one, the click wasn't on a mention. - Read the mention from the element's
data-mention-idanddata-mention-type. A user mention also hasdata-user-id.
Enter or Space on the message text also calls onMentionsClick. Its target is the whole text, so the handler finds no mention and does nothing:
import type { CustomMentionHandler } from "stream-chat-react";
import { MessageList } from "stream-chat-react";
const handleMentionClick: CustomMentionHandler = (event, message) => {
const target = event.target as HTMLElement;
const mention = target.closest<HTMLElement>(".str-chat__message-mention");
if (!mention) return;
const { mentionId, mentionType } = mention.dataset;
if (mentionType === "user") {
const user = message.mentioned_users?.find(({ id }) => id === mentionId);
console.log("Open the profile of", user?.name ?? mentionId);
} else {
console.log("Clicked a", mentionType, "mention");
}
};
export const MessageListWithMentionClicks = () => (
<MessageList onMentionsClick={handleMentionClick} />
);In a thread, the parent message gets the list's handlers too.
To read a context from inside a mention, such as MessageContext, render a custom mention component through renderText.
Reference
- State: Mentions, Suggestions, Composer middleware and the MessageComposer API.
- UI: Message composer UI and Message UI.
- Props: Input UI, renderText function and MessageList.
- Hooks: Message hooks.