Types
The extension exports TypeScript types for working with suggestions.
SuggestionType
Public-facing suggestion type returned by the query API:
type SuggestionType = 'add' | 'delete' | 'replace' | 'markChange'SuggestionMarkType
Internal mark-level type stored on suggestion marks. Replace suggestions use separate mark types for their deletion and insertion parts:
type SuggestionMarkType = 'add' | 'delete' | 'replaceDeletion' | 'replaceInsertion' | 'markChange'SuggestionMarkChangeOperation
Operation stored in a mark-change suggestion:
type SuggestionMarkChangeOperation = 'added' | 'removed'SuggestionMarkChange
Describes one mark mutation stored on a markChange suggestion:
type SuggestionMarkChange = {
operation: SuggestionMarkChangeOperation
markName: string
markAttrs: Record<string, unknown> | null
}Suggestion
Represents a suggestion found in the document:
type Suggestion = {
id: string
type: SuggestionType
userId: string
createdAt: string
updatedAt: string
userMetadata: Record<string, unknown> | null
from: number
to: number
text: string
fullText: string
// Only present for 'replace' suggestions:
deletionRange?: { from: number; to: number }
insertionRange?: { from: number; to: number }
replacedText?: string
// Only present for 'markChange' suggestions:
markChanges?: SuggestionMarkChange[]
// Only present when the suggestion affects block-level nodes:
insertedNodes?: JSONContent[]
deletedNodes?: JSONContent[]
}createdAt— ISO 8601 timestamp of when the suggestion was first createdupdatedAt— ISO 8601 timestamp of the most recent edit within the suggestion. Falls back tocreatedAtfor legacy data that predates this field.
text vs fullText
text— the text authored by this suggestion alone, excluding text inserted by nested (stacked) suggestions layered on top of it. Forreplacesuggestions, this is the new (inserted) text.fullText— the complete, continuous text spanned by this suggestion's marks, including any text inserted by nested suggestions from other authors. Forreplacesuggestions, this is the new (inserted) text.
For the vast majority of suggestions (no stacking) text === fullText. They diverge only when another author has inserted text via a nested suggestion inside this one.
Note that text only drops text that a nested suggestion inserted. A nested delete or mark-change does not insert content, so it never reduces the outer author's text. For example, if author A inserts "hello" and author B deletes "ll" inside it, A's text is still "hello" — B's deletion didn't add any text that belongs to B.
Worked example
Author A inserts "Hello world", then author B inserts "great " before "world" (nested inside A's addition):
| Suggestion | text | fullText |
|---|---|---|
| A (add, user-1) | "Hello world" | "Hello great world" |
| B (add, user-2) | "great " | "great " |
import { findSuggestions } from '@tiptap-pro/extension-tracked-changes'
const suggestions = findSuggestions(editor)
const outer = suggestions.find(s => s.userId === 'user-1')
outer.text // "Hello world" → show this in a review sidebar
outer.fullText // "Hello great world" → use when you need the literal spanDefault to text when displaying "what this person changed" (review panels, comment threads, activity logs). Reach for fullText only when you need the exact contiguous text the mark covers in the document.
For replace suggestions:
textcontains the new (inserted) textreplacedTextcontains the old (deleted) textdeletionRangeandinsertionRangegive the exact positions of each partfromandtocover the full range of both parts
For markChange suggestions:
textcontains the affected text contentmarkChangescontains the tracked mark operations, including mark names and attrs
For block-level node suggestions (e.g. inserting or deleting a paragraph or heading):
textalways contains the actual text content of the affected node — never a[nodeName]placeholderinsertedNodescontains the full JSON representation of each inserted nodedeletedNodescontains the full JSON representation of each deleted node
Use insertedNodes and deletedNodes to inspect node types and attributes when building richer UIs, such as displaying a node type badge alongside the suggestion text.
SuggestionMarkAttrs
Attributes stored on the suggestion mark:
type SuggestionMarkAttrs = {
id: string
type: SuggestionMarkType
userId: string
createdAt: string
updatedAt: string
userMetadata: Record<string, unknown> | null
markChanges?: SuggestionMarkChange[] | null
}SuggestionChangedEventPayload
Payload for the trackedChanges:suggestionChanged event. Fires whenever any content-bearing field of a suggestion changes, including range positions, text, mark changes, or type.
type SuggestionChangedEventPayload = {
suggestionId: string
oldSuggestion: Suggestion
suggestion: Suggestion
transaction: Transaction
}oldSuggestion— snapshot of the suggestion before the changesuggestion— the current (updated) suggestiontransaction— the ProseMirror transaction that caused the change
SuggestionRangeChangedEventPayload
Payload for the trackedChanges:suggestionRangeChanged event. Fires only when a suggestion's document positions shift.
type SuggestionRangeChangedEventPayload = {
suggestionId: string
oldRange: { from: number; to: number }
newRange: { from: number; to: number }
suggestion: Suggestion
transaction: Transaction
}TrackedChangesOptions
Configuration options for the extension:
type TrackedChangesOptions = {
enabled: boolean
userId: string
userMetadata?: Record<string, unknown> | null
ignoredTrackingMarks: string[]
onSuggestionCreate?: (suggestion: Suggestion) => void
onSuggestionAccept?: (id: string) => void
onSuggestionReject?: (id: string) => void
}Type helpers
The extension exports constants and helper functions for working with suggestion types:
import {
SUGGESTION_TYPES,
isAddLikeType,
isDeleteLikeType,
isReplaceMarkType,
markTypeToSuggestionType,
} from '@tiptap-pro/extension-tracked-changes'
// Constants
SUGGESTION_TYPES.ADD // 'add'
SUGGESTION_TYPES.DELETE // 'delete'
SUGGESTION_TYPES.REPLACE_DELETION // 'replaceDeletion'
SUGGESTION_TYPES.REPLACE_INSERTION // 'replaceInsertion'
SUGGESTION_TYPES.MARK_CHANGE // 'markChange'
// Check if a mark type represents added content (matches 'add' and 'replaceInsertion')
isAddLikeType('add') // true
isAddLikeType('replaceInsertion') // true
// Check if a mark type represents deleted content (matches 'delete' and 'replaceDeletion')
isDeleteLikeType('delete') // true
isDeleteLikeType('replaceDeletion') // true
// Check if a mark type is one of the replace sub-types
isReplaceMarkType('replaceDeletion') // true
// Convert a mark-level type to the public-facing suggestion type
markTypeToSuggestionType('replaceDeletion') // 'replace'
markTypeToSuggestionType('add') // 'add'