In a fictional production handover, two colleagues are named Jordan Lee. One works in lighting and the other in wardrobe. The author needs to select the lighting colleague, and the saved handover needs to retain that person's identity even if their display name changes.
Keep the ID separate from the visible name
Use an authorized directory result with a stable identifier. This original local fixture illustrates the distinction:
const people = [
{ id: 'person-lighting-14', label: 'Jordan Lee', team: 'Lighting' },
{ id: 'person-wardrobe-29', label: 'Jordan Lee', team: 'Wardrobe' }
];
Show the team in the suggestion interface so the two entries are distinguishable. Pass only the intended node attributes when someone chooses a result:
// Inside the current suggestion popup's item-selection handler:
props.command({ id: person.id, label: person.label });
props is the active Suggestion lifecycle's props object and person is the selected result. Do not substitute a display name for the ID just because it makes a demo shorter. The extension's default text uses the label when available and otherwise the ID; rendering and identity serve different purposes. Mention implementation
Configure the match source and a real popup
For a current Tiptap setup with its base document extensions installed, configure Mention along these lines:
Mention.configure({
HTMLAttributes: { class: 'person-mention' },
suggestion: {
char: '@',
items: ({ query }) => people.filter(person =>
`${person.label} ${person.team}`
.toLowerCase().includes(query.toLowerCase())
),
render: renderPeopleMenu
}
});
Mention comes from @tiptap/extension-mention. Follow the extension's documented package dependencies for your installed release. renderPeopleMenu is your application's popup implementation, not a built-in Tiptap function. This configuration supplies matches but requires that implementation before users can choose them.
The Suggestion utility documents lifecycle hooks such as onStart, onUpdate, onKeyDown, and onExit. A useful popup displays the name and team, calls the current props.command() on selection, handles navigation and dismissal, and removes its UI on exit. Its positioning must follow the active editor and fit the narrow authoring screen.
Use text rendering for directory labels. A colleague's display name should not become executable HTML in the menu.
Handle remote search without selecting stale results
For an actual directory, return authorized matches from the server. The current Suggestion API supplies an AbortSignal to asynchronous items() calls and supports minimum query length and debounce options. Match those options to your installed version; older integration examples can use different behavior.
Pass the supplied signal to your request and account for canceled requests. Type a query for Jordan, change it to another person while the first response is pending, and confirm the older results do not replace the current list. Also test an empty result and a directory error; neither should silently select the first colleague.
Save and resolve the intended person
For the handover fixture, select the Lighting entry and inspect the mention's saved ID. Reopen the document with the Mention extension enabled and verify that it still points to person-lighting-14. The Tiptap document guide explains keeping a supported JSON or HTML representation and deliberately replacing loaded content.
A server that sends mention notifications must independently validate the mentioned IDs and the author's permissions. The editor node records a reference; it does not prove that a notification was sent. Decide how the reader should see a renamed, deleted, or inaccessible person without exposing restricted directory details.
Finish by asking the handover reviewer to distinguish the two Jordan entries and open the saved Lighting reference. The useful result is an unambiguous assignment in the document that the crew actually reads.