Introduction to the PubNub Chat SDK
The PubNub Chat SDK, available for TypeScript and JavaScript applications, exposes a set of APIs designed to make it easy to add powerful and flexible chat features to your app with minimum development. Chat options like quoting, mentioning users, channel references, threads, read receipts, and typing indicators are supported natively by the SDK, letting you build a full-fledged app quickly.
Please refer to our documentation and sample chat app to get started with the Chat SDK. Our tutorial will walk you through the basic functionality of the Chat SDK and touch on some more advanced features whilst our hosted demo will show the Chat SDK in action.
This how-to is part of a series of posts diving into some of the more powerful features of the PubNub Chat SDK. The series can be read in any order, but the list of related articles is below:
- How to Manage User Channel Membership with the Chat SDK
- How to Add Reactions and Emojis to Messages with the Chat SDK
- How to Create Threads and Quote Messages with the Chat SDK
- How to Mention Users and Channels with the Chat SDK
Mentioning Users and Channels
One of the most powerful features of the Chat SDK is the ability to mention both Users and Channels, providing the message recipient with full context about who and what was being mentioned (or tagged) and allowing them to take action. This enables you to, for example, allow the recipient to click on the tagged user to view their profile page or click on a tagged channel to view that channel. These interactive features are table stakes for a modern chat app and would require a lot of development effort to implement from scratch, but it is provided as a standard part of our Chat SDK.
The documentation describes this as Mentioning Users and Referencing Channels. It gives you all the necessary details, but personally, I needed to see a working demo of the feature before I understood it correctly.
The short demo below is designed to be self-contained and only shows how mentioning users and channels works; no messages are sent over PubNub, and the ‘preview’ is rendered locally. This is done to focus on the key features.
Try typing a message and notice whenever you type ‘@’ followed by the first three letters of one of the test users, you will be prompted to “add” that user to the message. After adding a user, the demo preview will show them as a hyperlink (the link doesn’t go anywhere, and you can render the tagged user however you like in your own application; you are not limited to hyperlinks). Use the arrow keys to navigate around the text field; if you key the caret into a tagged user, you are given the option to “remove” that user from the message.
Try also typing ‘#’ followed by the first three letters of one of the test channels (case is unimportant), giving you the option to “add” the channel to the message. Added channels are rendered in bold, but, like users, you can render the channel however you like.
Finally, try typing a hyperlink and notice it is rendered as a clickable link in the recipient - the underlying functionality for this was provided automatically by the Chat SDK.
Interactive Demo
If the embedded content is not available on this page, it can also be viewed at https://chat-sdk-how-to-mentions.netlify.app/
The code that drives this demo is available on GitHub, but the rest of this article will describe how it was built.
Prerequisites
Ensure you have an instance of the Chat object instantiated in your app
const chat = await Chat.init({
publishKey: "YOUR_PUBLISH_KEY",
subscribeKey: "YOUR_SUBSCRIBE_KEY",
userId: "YOUR_USER_ID",
})
There are a lot of possible parameters you can pass to the Chat SDK, but for mentioning users and channels, you do not need anything more than the standard publish key, subscribe key, and user ID. If all of this is new to you, and you’re not sure where to get started, please check out the initial configuration section in our documentation.
Mentioning Users
The documentation for mentioning users references the MessageDraft in almost every sample and method, so it is important to understand the purpose of MessageDraft. MessageDraft is a fundamental type in the Chat SDK that enables you to provide context to your messages - examples of context include any files contained within the messages, any other messages that have been quoted, and any Users or Channels tagged in the message. Providing context to your messages allows a feature-rich experience for your users and the MessageDraft mechanism allows the Chat SDK to provide you with all the information your app needs to build an engaging user experience.
Firstly, every time you compose a new message, i.e., when your application initializes and after sending any message, you will need to create a new MessageDraft object. You can choose whether users will be suggested either ‘globally’ or only suggested from those users who are members of the ‘channel’
setNewMessageDraft(channel.createMessageDraft({ userSuggestionSource: "channel"}))
Having created the MessageDraft object, we need to provide it with any characters the user types in their message; this is done by calling the MessageDraft.onChange() function whenever the typed text changes. The following code is an example of the field onChange() handler
async function handleInput(event: React.FormEvent<HTMLInputElement>)
{
if (!newMessageDraft) return
const response = await newMessageDraft.onChange(event.currentTarget.value)
if (response.users.suggestedUsers?.length > 0)
{
setSuggestedUsers(response.users.suggestedUsers)
setNameOccurrenceIndex(response.users.nameOccurrenceIndex)
}
else
{
setSuggestedUsers([])
setNameOccurrenceIndex(-1)
}
… // Also handle channels (omitted for brevity)
setRenderedMessage(newMessageDraft.getMessagePreview())
}
A lot is happening in this change handler, so let’s break it down:
The line:
const response = await newMessageDraft.onChange(event.currentTarget.value)
Will be called whenever the input text changes and will return an array of suggested Users, if there are any appropriate suggestions (i.e., if you typed ‘@mar’, it will suggest ‘Marian,’ ‘Mary’ etc.) If there are suggested Users, we want to show them to the application user and keep track of the ‘nameOccurrenceIndex’ associated with these suggestions. The ‘nameOccurrenceIndex’ will increment every time you type an ‘@’ character and is used by the Chat SDK to determine which suggestions are being made.
When the application user picks a suggested user, the following code is called:
async function pickSuggestedUser(user:User)
{
if (!newMessageDraft) return
newMessageDraft.addMentionedUser(
user,
nameOccurrenceIndex
)
setText(newMessageDraft.value)
setRenderedMessage(newMessageDraft.getMessagePreview())
setSuggestedUsers([])
setNameOccurrenceIndex(-1)
inputRef.current?.focus()
}
The important call here is to messageDraft.addMentionedUser(), which will tell the Chat SDK which User is represented by the specified ‘@’ symbol
Note also the call to setText(newMessageDraft.value); this will update the input field to reflect the chosen user and is required for everything to work reliably and be intuitive for the user.
What about removing a user? The demo app will track where the caret is in the input field and use the Chat SDK API getHighlightedMention() to return which user’s details are currently being highlighted. If a user is being highlighted, the application user is given the option to remove that user, which is accomplished by calling the removeMentionedUser() API
Although this demo only renders a message preview using getMessagePreview(), in production, you would also call send() on the MessageDraft object to convey it to the recipient.
Referencing Channels
The exact same principles for mentioning users are used when referencing channels, with only the method names and parameters changing. You should use the same instance of the MessageDraft object for mentioning both Channels and Users.
To revisit the field onChange() handler, the code will look as follows:
async function handleInput(event: React.FormEvent<HTMLInputElement>)
{
if (!newMessageDraft) return
const response = await newMessageDraft.onChange(event.currentTarget.value)
… // Also handle users (omitted for brevity)
if (response.channels.suggestedChannels?.length > 0)
{
setSuggestedChannels(response.channels.suggestedChannels)
setLastAffectedChannelOccurrenceIndex(response.channels.channelOccurrenceIndex)
}
else
{
setSuggestedChannels([])
setLastAffectedChannelOccurrenceIndex(-1)
}
setRenderedMessage(newMessageDraft.getMessagePreview())
}
When the application user picks a suggested channel, the following code is called:
async function pickSuggestedChannel(channel:Channel)
{
if (!newMessageDraft) return
newMessageDraft.addReferencedChannel(channel, lastAffectedChannelOccurrenceIndex)
setText(newMessageDraft.value)
setRenderedMessage(newMessageDraft.getMessagePreview())
setSuggestedChannels([])
setLastAffectedChannelOccurrenceIndex(-1)
inputRef.current?.focus()
}
The important call here is to messageDraft.addReferencedChannel(), which will tell the Chat SDK which Channel is represented by the specified ‘#’ symbol.
Similar to picking users, the call to setText(newMessageDraft.value) will update the input field to reflect the chosen channel and is required for everything to work reliably and be intuitive for the user.
Although this demo does not support it, the Chat SDK also supports removing channel references and other capabilities. Please see the Channel References documentation for a full list of features.
Rendering Mentioned Users and Channels
The documentation will describe some message rendering logic, but I found the most elegant example is provided by the Chat SDK getting started application, so I essentially copied that for this demo. The Chat SDK allows you to access the different ‘parts’ within the message, which are exposed as ‘MixedTextTypedElement’ types and accessed through the message.getLinkedText() method.
The demo specifies a React useCallback to specify how each of these ‘parts’ are rendered:
const renderMessagePart = useCallback((messagePart: MixedTextTypedElement) => {
if (messagePart.type === "text") {
return messagePart.content.text
}
if (messagePart.type === "plainLink") {
return <a href={messagePart.content.link}>{messagePart.content.link}</a>
}
if (messagePart.type === "textLink") {
return <a href={messagePart.content.link}>{messagePart.content.text}</a>
}
if (messagePart.type === "mention") {
return <span><a href={`https://pubnub.com/users/${messagePart.content.id}`}>{messagePart.content.name}</a> </span>
}
if (messagePart.type === "channelReference") {
return <b>#{messagePart.content.name} </b>
}
return ""
}, [])
The demo’s rendering is simplistic: hyperlinks are converted to clickable links, user mentions are also made into clickable links (though these do not point to real URLs), and channel references are made bold.
Demo: Mention Users and Channels with our React Native demo on Mobile
You can play with these features using our Chat SDK Demo for Mobile, available as a hosted demo with complete source code on GitHub. You should also see the demo rendered in an iFrame at the bottom of this section.
- Log into the application, choosing a random user ID for each device. Make a mental note of the user IDs
- Start a conversation from the second device, selecting the user logged into the first device.
- Type ‘@’ followed by the first three characters of one of the user IDs you logged in as. Select the user from the presented drop-down.
- Notice how the received message will render the user’s name as a hyperlink
- Navigate to the ‘Mentions’ tab for the mentioned user and notice how the message that mentions that user is shown.
- You can also type a URL into a message in the demo app to see it rendered as a hyperlink, e.g., http://www.pubnub.com
If the embedded content is not available on this page, it can also be viewed at https://pubnubdevelopers.github.io/Chat-SDK-Demo/mobile/
How can PubNub help you?
This article was originally published on PubNub.com
Our platform helps developers build, deliver, and manage real-time interactivity for web apps, mobile apps, and IoT devices.
The foundation of our platform is the industry's largest and most scalable real-time edge messaging network. With over 15 points-of-presence worldwide supporting 800 million monthly active users, and 99.999% reliability, you'll never have to worry about outages, concurrency limits, or any latency issues caused by traffic spikes.
Experience PubNub
Check out Live Tour to understand the essential concepts behind every PubNub-powered app in less than 5 minutes
Get Setup
Sign up for a PubNub account for immediate access to PubNub keys for free
Get Started
The PubNub docs will get you up and running, regardless of your use case or SDK
Top comments (0)