Skip to Content

Mentions

reachat ships rich text input with @ mention support powered by TiptapΒ . Users can mention people, teams, channels β€” anything you want β€” by typing @ followed by a search query.

Overview

The mention feature provides:

  • Floating suggestion popup with keyboard navigation
  • Dynamic/async search for mentions
  • Customizable mention items with icons and descriptions
  • Custom rendering for mention suggestions
  • Full keyboard support (arrow keys, enter, escape)

Basic Usage

To enable mentions, configure the RichTextInput component with a mentions prop:

import { RichTextInput } from 'reachat'; const mentionItems = [ { id: '1', label: 'John Doe', description: 'Product Manager' }, { id: '2', label: 'Jane Smith', description: 'Engineering Lead' }, { id: '3', label: 'Engineering Team', description: 'Team mention' } ]; <RichTextInput mentions={{ trigger: '@', items: mentionItems }} onSubmit={(value) => console.log(value)} />

Configuration Options

The mentions prop accepts a SuggestionConfig object with the following options:

Static Items

<RichTextInput mentions={{ trigger: '@', items: [ { id: 'user1', label: 'Alice Johnson', description: 'Senior Developer', icon: <UserIcon /> }, { id: 'user2', label: 'Bob Williams', description: 'Design Lead' } ], maxResults: 5 }} />

For large datasets or remote data sources, use the onSearch callback:

<RichTextInput mentions={{ trigger: '@', onSearch: async (query) => { const response = await fetch(`/api/users?q=${query}`); const users = await response.json(); return users.map(user => ({ id: user.id, label: user.name, description: user.role, metadata: { email: user.email } })); }, maxResults: 10 }} />

Custom Selection Handler

Control what happens when a mention is selected:

<RichTextInput mentions={{ trigger: '@', items: mentionItems, onSelect: (item, insertText) => { // Custom logic before inserting console.log('Mentioned:', item); // Insert custom format insertText(`@${item.label} `); } }} />

Custom Rendering

Customize how mentions appear in the suggestion list:

<RichTextInput mentions={{ trigger: '@', items: mentionItems, renderItem: (item, isHighlighted) => ( <div style={{ padding: '8px 12px', backgroundColor: isHighlighted ? '#f0f0f0' : 'transparent', display: 'flex', alignItems: 'center', gap: '8px' }}> {item.icon} <div> <div style={{ fontWeight: 'bold' }}>{item.label}</div> <div style={{ fontSize: '12px', color: '#666' }}> {item.description} </div> </div> </div> ), renderEmpty: (query) => ( <div style={{ padding: '8px 12px', color: '#999' }}> No users found matching "{query}" </div> ) }} />

Using with ChatInput

The ChatInput component automatically supports mentions when configured:

import { Chat, ChatInput } from 'reachat'; <Chat sessions={sessions} activeSessionId={activeId} > <SessionMessagePanel> <SessionMessagesHeader /> <SessionMessages /> <ChatInput mentions={{ trigger: '@', onSearch: searchUsers, renderItem: (item, isHighlighted) => ( <MentionItemComponent item={item} highlighted={isHighlighted} /> ) }} /> </SessionMessagePanel> </Chat>

Advanced Examples

Multiple Trigger Characters

You can combine mentions with commands and other triggers:

<RichTextInput mentions={{ trigger: '@', items: userMentions }} commands={{ trigger: '/', items: slashCommands }} />

Metadata and Custom Actions

Store additional data with mentions:

const mentions = { trigger: '@', items: [ { id: 'channel1', label: 'general', description: 'General discussion', metadata: { type: 'channel', memberCount: 150 } } ], onSelect: (item, insertText) => { if (item.metadata?.type === 'channel') { // Special handling for channel mentions insertText(`#${item.label} `); } else { insertText(`@${item.label} `); } } };

Keyboard Navigation

Users can navigate the mention list using:

  • Arrow Up/Down: Move selection
  • Enter: Select current item
  • Escape: Close suggestion popup
  • Continue typing: Filter results

API Reference

SuggestionConfig Interface

NameTypeDefault
triggerstring

The character that triggers this suggestion (e.g., ’@’, ’/’, ’#’)

itemsT[]

Static list of available items for this trigger

onSearch(query: string) => T[] | Promise<T[]>

Async function to fetch items dynamically based on query

onSelect(item: T, insertText: (text: string) => void) => void

Callback when an item is selected

maxResultsnumber

Maximum items to show in the popup (default: 10)

renderItem(item: T, isHighlighted: boolean) => ReactNode

Custom render function for items

renderEmpty(query: string) => ReactNode

Custom render function for empty state

MentionItem Interface

NameTypeDefault
valuestring

The value to insert when mention is selected Defaults to

idstring

Unique identifier for the item

labelstring

Display name/label for the item

descriptionstring

Optional description for additional context

iconReactElement<unknown, string | JSXElementConstructor<any>>

Optional icon to display next to the item

metadataRecord<string, unknown>

Optional metadata for custom use cases

For more examples and interactive demos, visit the storybook demosΒ .