The configuration system provides flexible setup options for mention functionality including feed configuration, keyboard behavior, and dropdown appearance.
The primary configuration interface for the mention feature.
/**
* The configuration of the mention feature.
* Used in editor configuration under the 'mention' key.
*/
interface MentionConfig {
/**
* The list of mention feeds supported by the editor.
* Each feed must use a different marker character.
*/
feeds: Array<MentionFeed>;
/**
* Custom commit keys for confirming mention selection.
* @default [13, 9] // [Enter, Tab]
*/
commitKeys?: Array<number>;
/**
* Maximum number of visible mentions in dropdown.
* @default 10
*/
dropdownLimit?: number;
}Usage Examples:
import { ClassicEditor } from "@ckeditor/ckeditor5-editor-classic";
import { Mention } from "@ckeditor/ckeditor5-mention";
ClassicEditor.create(editorElement, {
plugins: [Mention],
mention: {
feeds: [
{
marker: '@',
feed: ['@alice', '@bob', '@charlie']
},
{
marker: '#',
feed: async (searchString) => {
return await fetchHashtags(searchString);
}
}
],
commitKeys: [13, 32], // Enter and Space
dropdownLimit: 15
}
});Configuration for individual mention feeds that define how mentions are triggered and populated.
/**
* The mention feed descriptor defining a single mention type.
* Each feed handles one marker character (like '@' or '#').
*/
interface MentionFeed {
/**
* The character which triggers autocompletion for mention.
* Must be a single character.
*/
marker: string;
/**
* Autocomplete items. Provide an array for static configuration
* or a function for dynamic data retrieval.
*/
feed: Array<MentionFeedItem> | MentionFeedbackCallback;
/**
* Minimum characters after marker before showing suggestions.
* @default 0
*/
minimumCharacters?: number;
/**
* Custom function for rendering mention items in dropdown.
*/
itemRenderer?: MentionItemRenderer;
/**
* Feed-specific dropdown limit, overrides global dropdownLimit.
*/
dropdownLimit?: number;
}Usage Examples:
// Static feed with simple strings
const userFeed: MentionFeed = {
marker: '@',
feed: ['@alice', '@bob', '@charlie', '@david'],
minimumCharacters: 2
};
// Dynamic feed with async callback
const hashtagFeed: MentionFeed = {
marker: '#',
feed: async (searchString: string) => {
const response = await fetch(`/api/hashtags?q=${searchString}`);
const hashtags = await response.json();
return hashtags.map(tag => `#${tag.name}`);
},
minimumCharacters: 1,
dropdownLimit: 20
};
// Feed with object items and custom renderer
const mentionFeed: MentionFeed = {
marker: '@',
feed: [
{ id: '@alice', text: 'Alice Johnson', avatar: '/avatars/alice.jpg' },
{ id: '@bob', text: 'Bob Wilson', avatar: '/avatars/bob.jpg' }
],
itemRenderer: (item) => {
const div = document.createElement('div');
div.innerHTML = `
<img src="${item.avatar}" alt="${item.text}" />
<span>${item.text}</span>
`;
return div;
}
};Types that define the structure of mention feed items.
/**
* Union type representing a mention feed item.
* Can be a simple string or a structured object.
*/
type MentionFeedItem = string | MentionFeedObjectItem;
/**
* Object-based mention item with required ID and optional display text.
*/
interface MentionFeedObjectItem {
/**
* Unique ID of the mention. Must start with the marker character.
*/
id: string;
/**
* Text inserted into the editor when creating a mention.
* If not provided, the id will be used.
*/
text?: string;
/**
* Additional properties for custom data storage.
*/
[key: string]: unknown;
}Function types for dynamic mention data retrieval and custom rendering.
/**
* Function that returns mention items based on search input.
* Can return items synchronously or asynchronously via Promise.
*/
type MentionFeedbackCallback = (
searchString: string
) => Array<MentionFeedItem> | Promise<Array<MentionFeedItem>>;
/**
* Function that renders a mention item as an HTML element or string.
* Used for customizing the appearance of items in the dropdown.
*/
type MentionItemRenderer = (
item: MentionFeedObjectItem
) => HTMLElement | string;Usage Examples:
// Synchronous callback
const syncFeed: MentionFeedbackCallback = (searchString) => {
const allUsers = ['@alice', '@bob', '@charlie', '@david'];
return allUsers.filter(user =>
user.toLowerCase().includes(searchString.toLowerCase())
);
};
// Asynchronous callback with error handling
const asyncFeed: MentionFeedbackCallback = async (searchString) => {
try {
const response = await fetch(`/api/users/search?q=${searchString}`);
if (!response.ok) throw new Error('Failed to fetch users');
const users = await response.json();
return users.map(user => ({
id: `@${user.username}`,
text: user.displayName,
userId: user.id,
department: user.department
}));
} catch (error) {
console.error('Error fetching mention feed:', error);
return [];
}
};
// Custom item renderer with rich HTML
const customRenderer: MentionItemRenderer = (item) => {
const wrapper = document.createElement('div');
wrapper.className = 'custom-mention-item';
if (typeof item === 'object' && item.avatar) {
wrapper.innerHTML = `
<img src="${item.avatar}" class="mention-avatar" />
<div class="mention-info">
<div class="mention-name">${item.text || item.id}</div>
<div class="mention-role">${item.role || ''}</div>
</div>
`;
} else {
wrapper.textContent = item.text || item.id;
}
return wrapper;
};// Configuration with different mention types
const config: MentionConfig = {
feeds: [
// User mentions
{
marker: '@',
feed: fetchUsers,
minimumCharacters: 2,
itemRenderer: renderUser
},
// Hashtag mentions
{
marker: '#',
feed: fetchHashtags,
minimumCharacters: 1
},
// Issue references
{
marker: '#',
feed: fetchIssues,
minimumCharacters: 0
}
],
commitKeys: [13, 9, 32], // Enter, Tab, Space
dropdownLimit: 12
};// Complex feed with caching and debouncing
const createAdvancedFeed = (): MentionFeed => {
const cache = new Map<string, MentionFeedItem[]>();
return {
marker: '@',
feed: async (searchString: string) => {
// Check cache first
if (cache.has(searchString)) {
return cache.get(searchString)!;
}
// Fetch from API
const results = await fetchWithRetry(`/api/users?q=${searchString}`);
cache.set(searchString, results);
return results;
},
minimumCharacters: 2,
dropdownLimit: 10,
itemRenderer: (item) => {
// Custom rendering with accessibility
const button = document.createElement('button');
button.setAttribute('role', 'option');
button.setAttribute('aria-label', `Mention ${item.text || item.id}`);
button.textContent = item.text || item.id;
return button;
}
};
};