Utilities
The extension exports utility functions for querying and working with suggestions.
findSuggestions()
Find all suggestions in the document, with optional filtering.
| Argument | Type | Default | Description |
|---|---|---|---|
editor | Editor | — | The Tiptap editor instance |
markName | string | 'suggestion' | The name of the suggestion mark |
options | FindSuggestionsOptions | {} | Optional filters (see below) |
Options
| Option | Type | Description |
|---|---|---|
type | 'add' | 'delete' | 'replace' | Filter by suggestion type |
userId | string | Filter by user ID |
id | string | Filter by suggestion ID |
Returns
Suggestion[] — Array of suggestions found in the document.
import { findSuggestions } from '@tiptap-pro/extension-tracked-changes'
// Find all suggestions
const allSuggestions = findSuggestions(editor)
// Find suggestions by type
const insertions = findSuggestions(editor, 'suggestion', { type: 'add' })
const deletions = findSuggestions(editor, 'suggestion', { type: 'delete' })
const replacements = findSuggestions(editor, 'suggestion', { type: 'replace' })
// Find suggestions by user
const userSuggestions = findSuggestions(editor, 'suggestion', { userId: 'user-123' })findSuggestionById()
Find a specific suggestion by ID.
| Argument | Type | Default | Description |
|---|---|---|---|
editor | Editor | — | The Tiptap editor instance |
id | string | — | The suggestion ID to find |
markName | string | 'suggestion' | The name of the suggestion mark |
Returns
Suggestion | undefined — The suggestion if found, undefined otherwise.
import { findSuggestionById } from '@tiptap-pro/extension-tracked-changes'
const suggestion = findSuggestionById(editor, 'suggestion-123')
if (suggestion) {
console.log(`Found suggestion: ${suggestion.text}`)
}findSuggestionRanges()
Find all document ranges covered by a suggestion. A single suggestion may span multiple text nodes when it crosses formatting boundaries.
| Argument | Type | Default | Description |
|---|---|---|---|
editor | Editor | — | The Tiptap editor instance |
id | string | — | The suggestion ID to find |
markName | string | 'suggestion' | The name of the suggestion mark |
Returns
Array<{ from: number; to: number }> — Array of position ranges covered by this suggestion. Adjacent ranges are automatically merged.
import { findSuggestionRanges } from '@tiptap-pro/extension-tracked-changes'
const ranges = findSuggestionRanges(editor, 'suggestion-123')
// Returns: [{ from: 10, to: 25 }, { from: 30, to: 35 }]getSuggestionAtSelection()
Get the suggestion at the current selection position. Works with both mark-based suggestions (text) and attribute-based suggestions (atom nodes).
| Argument | Type | Default | Description |
|---|---|---|---|
editor | Editor | — | The Tiptap editor instance |
markName | string | 'suggestion' | The name of the suggestion mark |
Returns
Suggestion | undefined — The suggestion at the current cursor position, or undefined if none.
import { getSuggestionAtSelection } from '@tiptap-pro/extension-tracked-changes'
const suggestion = getSuggestionAtSelection(editor)
if (suggestion) {
// Show accept/reject buttons in your UI
showSuggestionPopup(suggestion)
}getSuggestionAtPosition()
Get the suggestion at a specific document position.
| Argument | Type | Default | Description |
|---|---|---|---|
editor | Editor | — | The Tiptap editor instance |
pos | number | — | The document position to check |
markName | string | 'suggestion' | The name of the suggestion mark |
Returns
Suggestion | null — The suggestion at the position, or null if none found.
import { getSuggestionAtPosition } from '@tiptap-pro/extension-tracked-changes'
const suggestion = getSuggestionAtPosition(editor, 42)findSuggestionsInRange()
Find all suggestions that overlap with a specific document range.
| Argument | Type | Default | Description |
|---|---|---|---|
editor | Editor | — | The Tiptap editor instance |
from | number | — | Start position of the range |
to | number | — | End position of the range |
filters | { userId?: string; type?: SuggestionType } | undefined | Optional filters |
markName | string | 'suggestion' | The name of the suggestion mark |
Returns
Suggestion[] — Array of suggestions overlapping the range.
import { findSuggestionsInRange } from '@tiptap-pro/extension-tracked-changes'
// Find all suggestions between positions 10 and 50
const suggestions = findSuggestionsInRange(editor, 10, 50)
// With filters
const userInsertions = findSuggestionsInRange(editor, 10, 50, {
userId: 'user-123',
type: 'add',
})suggestionExists()
Check whether a suggestion still exists in the document.
| Argument | Type | Default | Description |
|---|---|---|---|
editor | Editor | — | The Tiptap editor instance |
suggestionId | string | — | The suggestion ID to check |
markName | string | 'suggestion' | The name of the suggestion mark |
Returns
boolean — true if the suggestion exists.
import { suggestionExists } from '@tiptap-pro/extension-tracked-changes'
if (suggestionExists(editor, 'suggestion-123')) {
// Suggestion is still in the document
}getSuggestionRange()
Get the bounding position range of a suggestion.
| Argument | Type | Default | Description |
|---|---|---|---|
editor | Editor | — | The Tiptap editor instance |
suggestionId | string | — | The suggestion ID |
markName | string | 'suggestion' | The name of the suggestion mark |
Returns
{ from: number; to: number } | null — The bounding range, or null if not found.
import { getSuggestionRange } from '@tiptap-pro/extension-tracked-changes'
const range = getSuggestionRange(editor, 'suggestion-123')
if (range) {
console.log(`Suggestion spans from ${range.from} to ${range.to}`)
}acceptSuggestions()
Accept multiple suggestions by their IDs. Processes each suggestion individually.
| Argument | Type | Description |
|---|---|---|
editor | Editor | The Tiptap editor instance |
suggestionIds | string[] | Array of suggestion IDs to accept |
Returns
boolean — true if at least one suggestion was accepted.
import { acceptSuggestions } from '@tiptap-pro/extension-tracked-changes'
acceptSuggestions(editor, ['suggestion-1', 'suggestion-2', 'suggestion-3'])rejectSuggestions()
Reject multiple suggestions by their IDs. Processes each suggestion individually.
| Argument | Type | Description |
|---|---|---|
editor | Editor | The Tiptap editor instance |
suggestionIds | string[] | Array of suggestion IDs to reject |
Returns
boolean — true if at least one suggestion was rejected.
import { rejectSuggestions } from '@tiptap-pro/extension-tracked-changes'
rejectSuggestions(editor, ['suggestion-1', 'suggestion-2'])generateSuggestionId()
Generate a unique suggestion ID. Combines timestamp with random string for uniqueness.
Returns
string — A unique suggestion ID in the format suggestion-{timestamp}-{random}.
import { generateSuggestionId } from '@tiptap-pro/extension-tracked-changes'
const id = generateSuggestionId()
// Returns: 'suggestion-1706621696789-k7x2m9p'getTimestamp()
Get the current time as an ISO 8601 timestamp string.
Returns
string — Current time as ISO 8601 string.
import { getTimestamp } from '@tiptap-pro/extension-tracked-changes'
const timestamp = getTimestamp()
// Returns: '2024-01-30T12:34:56.789Z'getSuggestionHTMLAttributes()
Reads suggestion data from a live ProseMirror node and returns the corresponding data-suggestion-* DOM attributes, safe to spread onto a NodeView's root element.
| Argument | Type | Description |
|---|---|---|
node | Node | The ProseMirror node received as the node prop in your NodeView component |
Returns
SuggestionHTMLAttributes — An object containing only the data-suggestion-* attributes derived from node.attrs. Keys whose value is null or undefined are omitted, so non-suggestion nodes return {}.
The attributes produced are:
| Output key | Source (node.attrs) |
|---|---|
data-suggestion-id | suggestionId |
data-suggestion-type | suggestionType |
data-suggestion-user | suggestionUserId |
data-suggestion-created | suggestionCreatedAt |
data-suggestion-updated | suggestionUpdatedAt |
data-suggestion-user-metadata | suggestionUserMetadata (JSON-serialized) |
data-suggestion-nesting-delta | suggestionNestingDelta |
Why node, not HTMLAttributes
The HTMLAttributes prop in a NodeView is computed once at creation time and never updated. Passing it to this utility would produce stale attributes whenever suggestion state changes — for example, after a remote collaboration update or when a suggestion is accepted or rejected. The node prop is the reactive source of truth and is updated on every render, so always pass node.
Usage
import { getSuggestionHTMLAttributes } from '@tiptap-pro/extension-tracked-changes'
function MyNodeView({ node }) {
const suggestionAttrs = getSuggestionHTMLAttributes(node)
return (
<div {...suggestionAttrs}>
Your content here
</div>
)
}For detailed guidance on integrating NodeViews with Tracked Changes, see the NodeView Support guide.