# Mentions

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

## 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. When the channel's members are searched locally, common accents are ignored, 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.

![Typing @rene suggests René](https://getstream.io/docs-assets/images/af97025c32c7.png)

There are five kinds of mention:

| Kind         | Typed as   | Notifies                | Message field                                                    |
| ------------ | ---------- | ----------------------- | ---------------------------------------------------------------- |
| `user`       | `@<name>`  | one user                | `mentioned_users`                                                |
| `channel`    | `@channel` | everyone in the channel | `mentioned_channel`                                              |
| `here`       | `@here`    | members who are online  | `mentioned_here`                                                 |
| `role`       | `@<role>`  | users with that role    | `mentioned_roles`                                                |
| `user_group` | `@<group>` | members of a user group | `mentioned_group_ids` when sending, `mentioned_groups` when read |

## How it works across the layers

### State: the text composer

The user types "Thanks @be" in "Design":

1. The text composer runs its middleware on every change. The mentions middleware finds the `@be` before the cursor and asks `MentionsSearchSource` for suggestions.
2. The search source collects them:
- **Users.** When the channel has fewer than 100 members loaded, it searches them locally, by name and id. Otherwise it queries the channel's members by name. With `mentionAllAppUsers`, it queries all users of the app instead.
- **`@channel` and `@here`**, when "be" starts their name.
- **Roles** through `client.searchRoles()`, and **user groups** through `client.searchUserGroups()`, scoped to the channel's team. Both need at least one character after `@`.
3. The suggestions land in the text composer's state as `suggestions`, and the UI lists them.
4. The user picks Ben. The middleware replaces `@be` with `@Ben` and adds Ben to the text composer's `mentions`.
5. When they send, the composer writes each mention to the message field of its kind, from the table above.

Each kind other than `user` is offered only when the user has its capability in the channel (see Turning it on or off). The capabilities are checked on every search, so the suggestions follow when they change.

The middleware and the search source are explained on [Suggestions](https://getstream.io/chat/docs/sdk/react/v15/state/writing-messages/suggestions/#mentions).

### UI: suggestions and highlighting

The input, `TextareaComposer`, renders the suggestion list while the text composer has suggestions:

- `AutocompleteSuggestionList`, by default `SuggestionList`, lists them and handles the keyboard.
- Each row is an `AutocompleteSuggestionItem`. For `@`, the row renders `MentionItem`, which picks `UserItem`, `BroadcastMentionItem` (`@channel` and `@here`), `RoleItem` or `UserGroupItem`.

In the message list, the message text is rendered by `renderText`, which turns each mention into a `Mention` element:

```html
<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. See [The input](https://getstream.io/chat/docs/sdk/react/v15/ui/components/message-composer-ui/#the-input) for the composer side.

## Turning it on or off

User mentions are always available. The other kinds need a capability in the channel:

| Kind         | Capability       | Permission in the dashboard |
| ------------ | ---------------- | --------------------------- |
| `channel`    | `notify-channel` | `NotifyChannel`             |
| `here`       | `notify-here`    | `NotifyHere`                |
| `role`       | `notify-role`    | `NotifyRole`                |
| `user_group` | `notify-group`   | `NotifyGroup`               |

Grant them in the [Stream Dashboard](https://getstream.io/signin/?product=chat) 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](https://getstream.io/chat/docs/javascript/user-groups/).

## Customizing

### Changing the search

Give the mentions middleware a search source with other options, in a composer setup function. This one matches the typed text against names written in other scripts, using a `transliterate` function:

```ts
import transliterate from "@sindresorhus/transliterate";
import type { TextComposerMiddleware } from "stream-chat";
import { createMentionsMiddleware, MentionsSearchSource } from "stream-chat";

client.config.setSetupFunction("messageComposer", ({ composer }) => {
  const { channel, textComposer } = composer;
  const searchSource = new MentionsSearchSource(channel, { transliterate });

  // Same id as the default mentions middleware, so it takes its place.
  textComposer.middlewareExecutor.replace([
    createMentionsMiddleware(channel, {
      searchSource,
    }) as TextComposerMiddleware,
  ]);

  return () => {
    textComposer.middlewareExecutor.replace([
      createMentionsMiddleware(channel) as TextComposerMiddleware,
    ]);
  };
});
```

`transliterate` takes the text and returns it in Latin script, `(text: string) => string`. It applies where the search source compares names itself: the local member search and `@channel` and `@here`. Queries to the server aren't transliterated.

![Typing @ana suggests Анатолий](https://getstream.io/docs-assets/images/42c316740815.png)

Other options of `MentionsSearchSource`:

- `mentionAllAppUsers: true` suggests every user of the app, not only the channel's members.
- `memberFilters` replaces the default member query. `userFilters` adds conditions to the user query that `mentionAllAppUsers` makes.
- `memberSort` and `userSort` replace the default order.
- `pageSize` sets how many suggestions load at a time.

There is one setup function per kind, so this one replaces any other `messageComposer` setup function; do all composer setup in one. See [Replacing mention search](https://getstream.io/chat/docs/sdk/react/v15/state/writing-messages/suggestions/#replacing-mention-search).

### Replacing a suggestion row

Pass your own row components to `MentionItem`, and give the list the new `@` row through `SuggestionList`'s `suggestionItemComponents`:

```tsx
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](https://getstream.io/chat/docs/sdk/react/v15/recipes/composer/custom-suggestions/) recipe builds complete rows.

### Styling mentions

Each mention has `data-mention-type`, so CSS can style the kinds differently:

```css
.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](https://getstream.io/chat/docs/sdk/react/v15/component-reference/message/rendertext-function/#custom-element-rendering).

### Reacting to clicks and hovers

`onMentionsClick` and `onMentionsHover` receive the event, the message's mentioned users and the message. The second argument is deprecated: read the mention from the clicked element and the message instead. A handler runs for a click anywhere in the text, so check which element was clicked:

```tsx
import type { CustomMentionHandler } from "stream-chat-react";
import { MessageList } from "stream-chat-react";

const handleMentionClick: CustomMentionHandler = (
  event,
  _mentionedUsers,
  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} />
);
```

`VirtualizedMessageList` doesn't take these props. For it, or to reach other contexts such as `MessageContext`, use a custom `mention` component in `renderText` instead.

## Reference

- State: [Suggestions](https://getstream.io/chat/docs/sdk/react/v15/state/writing-messages/suggestions/), [Composer middleware](https://getstream.io/chat/docs/sdk/react/v15/state/writing-messages/composer-middleware/) and the [MessageComposer API](https://getstream.io/chat/docs/sdk/react/v15/reference/state/messagecomposer-api/).
- UI: [Message composer UI](https://getstream.io/chat/docs/sdk/react/v15/ui/components/message-composer-ui/#the-input) and [Message list UI](https://getstream.io/chat/docs/sdk/react/v15/ui/components/message-list-ui/#a-message).
- Props: [Input UI](https://getstream.io/chat/docs/sdk/react/v15/component-reference/message-composer/input-ui/), [renderText function](https://getstream.io/chat/docs/sdk/react/v15/component-reference/message/rendertext-function/) and [MessageList](https://getstream.io/chat/docs/sdk/react/v15/component-reference/message-list/messagelist/).
- Hooks: [Message hooks](https://getstream.io/chat/docs/sdk/react/v15/reference/hooks/message-hooks/).

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/v15/features/messaging/mentions/](https://getstream.io/chat/docs/sdk/react/v15/features/messaging/mentions/).