Mention users
The Mentions feature lets users tag specific individuals within a chat or conversation.
Chat SDK lets one user tag another user by adding @
and typing at least three first letters of the username they want to mention. As a result, they get a list of suggested usernames when typing such a suggestion, like @Mar
.
The list of returned users depends on your app configuration - these can be either all members in the channel where you write a message or all users of your app (user data taken from the Admin Portal keyset for your app). The number of returned suggested users for the mention also depends on your app configuration and can show up to 100
suggestions. The names of the suggested users can consist of multiple words and contain up to 200 characters.
You can configure your app to let users mention up to 100
users in a single message (default value is 10
) and configure mentions to be shown as links or display user details when highlighted (for example, by hovering over them).
For @
to be treated as a mention in the message, you must first map a given @
character to a specific user. Without it, @
will be treated as a regular string and will be shown as plain text.
You can implement mentions in your app in a similar way you would implement channel referencing.
Requires App Context
To mention users from a keyset, you must enable App Context for your app's keyset in the Admin Portal.
A sample implementation of mentions could include the following:
- Configure how a message with mentions (called "draft message") should behave - what should be the user metadata source and what should be the maximum number of mentions allowed in a single message.
- Add the
onChange
listener for the message input to track if there are any mentions in a message to handle. - Decide how many suggested users you want to show after typing the required string (
@
and at least three characters). - Add users to the list of mentioned users or remove users when at least one character of the mention is deleted.
- Handle draft messages publishing (text with mentioned user metadata).
- Optionally, show mentions in the published message as links and show user details when highlighting mentions.
Interactive demo
Check how a sample implementation could look like in a React app showcasing user mentions and channel references.
Want to implement something similar?
Read how to do that or go straight to the demo's source code.
Test it out
Type in @Mar
or @Man
in the input field and select one of the suggested users to mention.
Create message with mentions
createMessageDraft()
creates a message draft with mentioned users.
Whenever you mention a user, this user is added to the list of all mentioned users inside the MessageDraft
object. This draft contains the text content and all mentioned users and their names from the selected user metadata source (all channel members or all users on the app's keyset). Once you send this message (send()
), that information gets stored in the message metadata.
Method signature
Head over to the Drafts documentation for details on the method signature, input, and output parameters.
Basic usage
Create a message mentioning channel members @James, Sarah
and @Twain, Mark
.
const newMessageDraft = this.channel.createMessageDraft({ userSuggestionSource: "channel" })
const suggestedUsers = []
const lastAffectedNameOccurrenceIndex = -1
async handleInput(text: string) {
const response = await newMessageDraft.onChange(text)
suggestedUsers = response.users.suggestedUsers
lastAffectedNameOccurrenceIndex = response.users.nameOccurrenceIndex
}
handleInput("Hello @James, Sarah")
newMessageDraft.addMentionedUser(suggestedUsers[0], lastAffectedNameOccurrenceIndex)
handleInput("@Twain, Mark")
newMessageDraft.addMentionedUser(suggestedUsers[0], lastAffectedNameOccurrenceIndex)
Track mentions
onChange()
attached to the input message lets you control if there are any @
in the text followed by at least three letters.
If there are @
, you can configure your app to return suggested users whose names match the typed text and later add these suggested users to the correct @
.
Method signature
This method has the following signature:
messageDraft.onChange(text: string): Promise<{
users: {
nameOccurrenceIndex: number;
suggestedUsers: User[];
};
channels: {
channelOccurrenceIndex: number;
suggestedChannels: Channel[];
};
}>
Input
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
text | string | Yes | n/a | Typed in a message containing @ that is mapped to a specific user's name (or # for a channel reference). |
Output
Parameter | Type | Description |
---|---|---|
Promise<> | object | Returned object containing these fields: users (for @mentions) and channels (for #references). |
users | object | Returned object containing these fields for mentioned users: nameOccurrenceIndex and suggestedUsers . |
→ nameOccurrenceIndex | number | Specific occurrence of @ in the message (like 3 ) that is mapped to a given user. |
→ suggestedUsers | User[] | List of users that match the typed text after @ , like Mark for @Mar . |
channels | object | Returned object containing these fields for referenced channels: channelOccurrenceIndex and suggestedChannels . |
→ channelOccurrenceIndex | number | Specific occurrence of # in the message (like 3 ) that is mapped to a given channel. |
→ suggestedChannels | Channel[] | List of channels that match the typed text after # , like Support for #Sup . |
Basic usage
Track mentions for messages on the current channel.
const newMessageDraft = this.channel?.createMessageDraft()
async handleInput(text: string) {
const response = await newMessageDraft.onChange(text)
const suggestedUsers = response.users.suggestedUsers
const lastAffectedNameOccurrenceIndex = response.users.nameOccurrenceIndex
}
Get user suggestions
getUserSuggestions()
returns all suggested users that match the provided 3-letter string from a selected data source (channel members or global users on your app's keyset).
For example, if you type Sam
, you will get the list of users starting with Sam
like Samantha
or Samir
. The default number of returned suggested usernames is 10
which is configurable to a maximum value of 100
.
Method signature
This method can be called on two Chat SDK objects and has the following signature:
-
Called on the
Channel
objectchannel.getUserSuggestions(
text: string,
{
limit: number
}
): Promise<Membership[]> -
Called on the
Chat
objectchat.getUserSuggestions(
text: string,
{
limit: number
}
): Promise<User[]>
Input
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
text | string | Yes | n/a | At least a 3-letter string typed in after @ with the user name you want to mention. |
limit | number | Yes | 10 | Maximum number of returned usernames that match the typed 3-letter suggestion. The default value is set to 10 , and the maximum is 100 . |
Output
Type | Returned on Channel object | Returned on Chat object | Description |
---|---|---|---|
Promise<Membership[]> | Yes | No | Returned array of Membership objects. |
Promise<User[]> | No | Yes | Returned array of User objects. |
Basic usage
Return five channel users whose names start with Mar
.
chat.getUserSuggestions(
"@Mar, can you look at this ticket?",
{ limit: 5 }
)
Add mentioned user
For @
to be treated as a mention in the message, you must first map a given @
character to a specific user. Use the addMentionedUser()
method to create this mapping. Without it, @
will be treated as a regular string and will be shown as plain text.
Method signature
This method has the following signature:
messageDraft.addMentionedUser(
user: User,
nameOccurrenceIndex: number
): void
Input
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
user | User | Yes | n/a | User object that you want to map to a given occurrence of @ in the message. |
nameOccurrenceIndex | number | Yes | n/a | Specific occurrence of @ in the message (like 3 ) that you want to map to a given user. |
Output
Type | Description |
---|---|
void | Method returns no output data. |
Basic usage
Map @Twain, Mark
to the third @
in the message.
const response = await messageDraft.onChange("Hello @twai")
// let's say it returns { suggestedUsers: [user Mark Twain, someOtherUser...], nameOccurrenceIndex: 0 }
messageDraft.addMentionedUser(response.suggestedUsers[0], response.nameOccurrenceIndex)
Remove mentioned user
Use the removeMentionedUser()
method to remove the mapping between a specific occurrence of @Some User
in the message and a given user. Once you remove at least one character from a mention, this mention is automatically deleted, and @Some Us
becomes a regular string.
Method signature
This method has the following signature:
messageDraft.removeMentionedUser(
nameOccurrenceIndex: number
): void
Input
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
nameOccurrenceIndex | number | Yes | n/a | Specific occurrence of @ in the message (like 3 ) that you want to unmap from a given user. |
Output
Type | Description |
---|---|
void | Method returns no output data. |
Basic usage
Remove @Twain, Mark
from the third @
in the message.
messageDraft.removeMentionedUser(3)
Send message with mentions
send()
publishes the text message with mentioned users and emits events of type mention
.
Method signature
Head over to the Drafts documentation for details on the method signature, input, and output parameters.
Basic usage
Send the previously drafted message in which you mention users @James, Sarah
and @Twain, Mark
.
const newMessageDraft = this.channel.createMessageDraft({ userSuggestionSource: "channel" })
const suggestedUsers = []
const lastAffectedNameOccurrenceIndex = -1
async handleInput(text: string) {
const response = await newMessageDraft.onChange(text)
suggestedUsers = response.users.suggestedUsers
lastAffectedNameOccurrenceIndex = response.users.nameOccurrenceIndex
}
handleInput("Hello @James, Sarah")
newMessageDraft.addMentionedUser(suggestedUsers[0], lastAffectedNameOccurrenceIndex)
handleInput("Hello @James, Sarah and @Twain, Mark")
newMessageDraft.addMentionedUser(suggestedUsers[0], lastAffectedNameOccurrenceIndex)
show all 16 linesGet mentioned users
Use the mentionedUsers
getter method to return all users mentioned in a message.
Method signature
This method has the following signature:
message.mentionedUsers: {
id: string;
name: string
}[]
Properties
Property | Type | Description |
---|---|---|
mentionedUsers | array | Method can return a value of any type. |
Properties
Property | Type | Description |
---|---|---|
object | array | List of key-value pairs that stand for specific mentioned users. |
→ id | string | Unique identifier of the mentioned user. |
→ name | string | Name of the mentioned user. |
Basic usage
Check if the last message on the support
channel contains any mentions.
// reference the "support" channel
const channel = await chat.getChannel("support")
// get the last message on the channel
const lastMessage = (await channel.getHistory({count: 1})).messages[0]
// check if it contains any user mentions
message.mentionedUsers
Show user details on highlighting
getHighlightedMention()
returns the specific user details when moving the cursor above the mentioned user or returns null
if you move the cursor away.
Method signature
This method has the following signature:
messageDraft.getHighlightedMention(selectionStart: number): {
mentionedUser: null;
nameOccurrenceIndex: number;
} | {
mentionedUser: User;
nameOccurrenceIndex: number;
}
Input
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
selectionStart | number | Yes | n/a | Position of the cursor above the given mention (@ ) in the message. |
Output
Parameter | Type | Description |
---|---|---|
mentionedUser | User or null | Mentioned user mapped to the number of mention (nameOccurrenceIndex ) in the message, or a null value if no user is returned. |
nameOccurrenceIndex | number | Specific occurrence of @ in the message (like 3 ) that is mapped to a given user. |
Basic usage
Highlight a mention (if any) of the current caret position.
handleCaret(event: any) {
this.currentlyHighlightedMention = this.newMessageDraft.getHighlightedMention(
this.userInput?.nativeElement.selectionStart
)
}
Show mention as link
getMessageElements()
renders a user mention (like @Twain, Mark
) as a clickable link in the final, published message. If you want to customize the way these mentions render, you can create custom functions.
This is the same method that lets you render plain or text links or show referenced channels as links.
Method signature
Head over to the Links documentation for details on the method signature, input, and output parameters.
Basic usage
Show all linked mentions in a message as clickable links.
message.getMessageElements()
Other examples
Check how you can customize the default behavior of the Chat SDK methods and render the mentions differently.
Add company links
Add a link to a PubNub profile under each user mention.
- React
- React Native
- Vue
- Angular
const renderMessagePart = (messagePart: MixedTextTypedElement) => {
if (messagePart.type === "mention") {
// assuming messagePart.content.id is the user ID
const pubnubProfileUrl = `https://pubnub.com/profiles/${messagePart.content.id}`;
return (
<span>
<a href={pubnubProfileUrl}>{messagePart.content.name}</a>
{" "}
{/* add a space after the user mention */}
</span>
);
}
return "";
}
import React from 'react';
import { Text, Linking, View } from 'react-native';
const renderMessagePart = (messagePart) => {
if (messagePart.type === "mention") {
const pubnubProfileUrl = `https://pubnub.com/profiles/${messagePart.content.id}`;
return (
<View>
<Text>
<Text onPress={() => Linking.openURL(pubnubProfileUrl)}>
{messagePart.content.name}
</Text>
{" "}
</Text>
</View>
show all 20 lines<template>
<div>
<span v-for="messagePart in messageParts" :key="messagePart.content.id">
<template v-if="messagePart.type === 'mention'">
<a :href="getPubnubProfileUrl(messagePart.content.id)">{{ messagePart.content.name }}</a>
<!-- add a space after the user mention -->
</template>
</span>
</div>
</template>
<script>
export default {
data() {
return {
show all 27 linesimport { Component } from '@angular/core';
@Component({
selector: 'app-message',
template: `
<span>
<ng-container *ngFor="let messagePart of messageParts">
<ng-container *ngIf="messagePart.type==='mention'">
<a [href]="getPubnubProfileUrl(messagePart.content.id)">
{{ messagePart.content.name }}
</a>
</ng-container>
<ng-container *ngIf="messagePart.type!=='mention'">
<!-- render other message elements, like text:
show all 33 linesModify display color
Change the mentions display color from the default blue to green.
- React
- React Native
- Vue
- Angular
const renderMessagePart = (messagePart: MixedTextTypedElement) => {
if (messagePart.type === "mention") {
const linkStyle = {
color: "green", // set the color to green
// add any other desired styles here, e.g., textDecoration: "underline"
};
return (
<a href={`https://pubnub.com/${messagePart.content.id}`} style={linkStyle}>
{messagePart.content.name}
</a>
);
}
return "";
show all 16 linesimport React from 'react';
import { Text } from 'react-native';
const renderMessagePart = (messagePart) => {
if (messagePart.type === "mention") {
const linkStyle = {
color: "green", // set the color to green
// add any other desired styles here, e.g., textDecorationLine: "underline"
};
return (
<Text style={linkStyle}>
{messagePart.content.name}
</Text>
);
show all 19 lines<template>
<div>
<span v-for="messagePart in messageParts" :key="messagePart.id">
<a v-if="messagePart.type === 'mention'"" :href="`https://pubnub.com/${messagePart.content.id}`" :style="linkStyle">
{{ messagePart.content.name }}
</a>
<!-- render other message elements, like text:
<span v-else>
<span :style="color: green;" v-if="messagePart.type === 'text'">{{ messagePart.content.text }}</span>
</span> -->
</span>
</div>
</template>
<script>
show all 31 linesimport { Component } from '@angular/core';
@Component({
selector: 'app-message',
template: `
<ng-container *ngFor="let messagePart of messageParts">
<a *ngIf="messagePart.type === 'mention'"
[href]="'https://pubnub.com/' + messagePart.content.id"
style="color: green;">
{{ messagePart.content.name }}
</a>
</ng-container>
`,
})
export class MessageComponent {
show all 21 linesShow linked mention preview
getMessagePreview()
returns a list of message draft elements, such as: text, user mentions, referenced channels, plain URLs, or text URLs. You can decide how you want to render these elements in your app and format them separately. For example, you could use this method to map user mentions in your message to render as links to these users' profiles.
Method signature
Head to the Links documentation for details on the method signature, input, and output parameters.
Basic usage
Show a preview of the linked mention.
messageDraft.getMessagePreview()
For examples of how you can customize linked mention previews, refer to the getMessageElements()
method that's similar in structure but is meant for final, published messages.
Collect all user-related mentions
The getCurrentUserMentions()
method lets you collect in one place all instances when a specific user was mentioned by someone - either in channels or threads. You can use this info to create a channel with all user-related mentions.
Method signature
This method has the following signature:
chat.getCurrentUserMentions({
startTimetoken?: string;
endTimetoken?: string;
count?: number;
}): Promise<{
enhancedMentionsData: UserMentionData[];
isMore: boolean;
}>
Input
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
startTimetoken | string | No | n/a | Timetoken delimiting the start of a time slice (exclusive) to pull messages with mentions from. For details, refer to the Fetch History section. |
endTimetoken | string | No | n/a | Timetoken delimiting the end of a time slice (inclusive) to pull messages with mentions from. For details, refer to the Fetch History section. |
count | number | No | 100 | Number of historical messages with mentions to return in a single call. Since each call returns all attached message reactions by default, the maximum number of returned messages is 100 . For more details, refer to the description of the includeMessageActions parameter in the JavaScript SDK docs. |
Output
Parameter | Type | Description |
---|---|---|
Promise<> | object | Returned object containing two fields: enhancedMentionsData and isMore . |
→ enhancedMentionsData | UserMentionData[] (ChannelMentionData or ThreadMentionData ) | Array listing the requested number of historical mention events with a set of information that differ slightly depending on whether you were mentioned in the main (parent) channel or in a thread. For mentions in the parent channel, the returned ChannelMentionData includes these fields: event (of type mention ), channelId where you were mentioned, message that included the mention, userId that mentioned you. For mentions in threads, the returned ThreadMentionData includes similar fields, the only difference is that you'll get parentChannelId and threadChannelId fields instead of just channelId to clearly differentiate the thread that included the mention from the parent channel in which this thread was created. |
→ isMore | boolean | Info whether there are more historical events to pull. |
Basic usage
List the last ten mentions for the current chat user.
await chat.getCurrentUserMentions(
{
count: 10
}
)
Show notifications for mentions
You can monitor all events emitted when you are mentioned in a parent or thread channel you are a member of using the listenForEvents()
method. You can use this method to create pop-up notifications for the users.
Events documentation
To read more about the events of type mention
, refer to the Chat events documentation.
Method signature
This method has the following parameters:
chat.listenForEvents({
user: string;
type?: "mention";
callback: (event: Event<"mention">) => unknown;
}): () => void
Input
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
user | string | Yes | Channel equal to user ID | Channel to listen for new mention events. In the case of mention events, this channel is always the current user's ID. You can refer to it through chat.currentUser.id . |
type | string | No | n/a | Type of events. mention is the type defined for all mention-created events. |
callback | n/a | Yes | n/a | Callback function passed as a parameter. It defines the custom behavior to be executed whenever a mention event type is detected on the specified channel. |
channel | string | This parameter is deprecated. Use user instead. mention events. In the case of mention events, this channel is always the current user's ID. You can refer to it through chat.currentUser.id . | ||
method | string | This parameter is deprecated. You no longer have to provide a method used to send this event type as the method is now passed automatically. publish for all events related to reporting. |
Output
Type | Description |
---|---|
() => void | Function you can call to disconnect (unsubscribe) from the channel and stop receiving mention events. |
Basic usage
Print a notification for a mention of the current chat user on the support
channel.
const chat = {
listenForEvents: async (config) => {
const simulateEvent = () => {
const event = "mention";
const eventData = {
channel: "support",
user: "John",
message: "You have a new support request!",
};
if (event === config.type) {
config.callback(eventData);
}
};
// simulate a single event when listening starts
show all 28 linesShow mention as link (deprecated)
Alternative method
This method is deprecated. Use getMessageElements()
instead.
getLinkedText()
renders a user mention (like @Twain, Mark
) as a clickable link in the final, published message. If you want to customize the way these mentions render, you can create custom functions.
This is the same method that lets you render plain or text links or show referenced channels as links.
Method signature
Head over to the Links documentation for details on the method signature, input, and output parameters.
Basic usage
Show all linked mentions in a message as clickable links.
message.getLinkedText()
Other examples
Check how you can customize the default behavior of the Chat SDK methods and render the mentions differently.
Add company links
Add a link to a PubNub profile under each user mention.
- React
- React Native
- Vue
- Angular
const renderMessagePart = (messagePart: MixedTextTypedElement) => {
if (messagePart.type === "mention") {
// assuming messagePart.content.id is the user ID
const pubnubProfileUrl = `https://pubnub.com/profiles/${messagePart.content.id}`;
return (
<span>
<a href={pubnubProfileUrl}>{messagePart.content.name}</a>
{" "}
{/* add a space after the user mention */}
</span>
);
}
return "";
}
import React from 'react';
import { Text, Linking, View } from 'react-native';
const renderMessagePart = (messagePart) => {
if (messagePart.type === "mention") {
const pubnubProfileUrl = `https://pubnub.com/profiles/${messagePart.content.id}`;
return (
<View>
<Text>
<Text onPress={() => Linking.openURL(pubnubProfileUrl)}>
{messagePart.content.name}
</Text>
{" "}
</Text>
</View>
show all 20 lines<template>
<div>
<span v-for="messagePart in messageParts" :key="messagePart.content.id">
<template v-if="messagePart.type === 'mention'">
<a :href="getPubnubProfileUrl(messagePart.content.id)">{{ messagePart.content.name }}</a>
<!-- add a space after the user mention -->
</template>
</span>
</div>
</template>
<script>
export default {
data() {
return {
show all 27 linesimport { Component } from '@angular/core';
@Component({
selector: 'app-message',
template: `
<span>
<ng-container *ngFor="let messagePart of messageParts">
<ng-container *ngIf="messagePart.type==='mention'">
<a [href]="getPubnubProfileUrl(messagePart.content.id)">
{{ messagePart.content.name }}
</a>
</ng-container>
<ng-container *ngIf="messagePart.type!=='mention'">
<!-- render other message elements, like text:
show all 33 linesModify display color
Change the mentions display color from the default blue to green.
- React
- React Native
- Vue
- Angular
const renderMessagePart = (messagePart: MixedTextTypedElement) => {
if (messagePart.type === "mention") {
const linkStyle = {
color: "green", // set the color to green
// add any other desired styles here, e.g., textDecoration: "underline"
};
return (
<a href={`https://pubnub.com/${messagePart.content.id}`} style={linkStyle}>
{messagePart.content.name}
</a>
);
}
return "";
show all 16 linesimport React from 'react';
import { Text } from 'react-native';
const renderMessagePart = (messagePart) => {
if (messagePart.type === "mention") {
const linkStyle = {
color: "green", // set the color to green
// add any other desired styles here, e.g., textDecorationLine: "underline"
};
return (
<Text style={linkStyle}>
{messagePart.content.name}
</Text>
);
show all 19 lines<template>
<div>
<span v-for="messagePart in messageParts" :key="messagePart.id">
<a v-if="messagePart.type === 'mention'"" :href="`https://pubnub.com/${messagePart.content.id}`" :style="linkStyle">
{{ messagePart.content.name }}
</a>
<!-- render other message elements, like text:
<span v-else>
<span :style="color: green;" v-if="messagePart.type === 'text'">{{ messagePart.content.text }}</span>
</span> -->
</span>
</div>
</template>
<script>
show all 31 linesimport { Component } from '@angular/core';
@Component({
selector: 'app-message',
template: `
<ng-container *ngFor="let messagePart of messageParts">
<a *ngIf="messagePart.type === 'mention'"
[href]="'https://pubnub.com/' + messagePart.content.id"
style="color: green;">
{{ messagePart.content.name }}
</a>
</ng-container>
`,
})
export class MessageComponent {
show all 21 lines