---
title: "Utilities"
description: "Utility functions for querying and working with suggestions in the Tiptap Tracked Changes extension."
canonical_url: "https://tiptap.dev/docs/tracked-changes/api-reference/utilities"
---

# Utilities

Utility functions for querying and working with suggestions in the Tiptap Tracked Changes extension.

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.

```js
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.

```js
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.

```js
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.

```js
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.

```js
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.

```js
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.

```js
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.

```js
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.

```js
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.

```js
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}`.

```js
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.

```js
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

```jsx
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](https://tiptap.dev/docs/tracked-changes/guides/nodeview-support.md).
