---
title: "Creating an editor with Tracked Changes"
description: "Step-by-step guide to setting up a Tiptap editor with the Tracked Changes extension in React."
canonical_url: "https://tiptap.dev/docs/tracked-changes/guides/editor-setup"
---

# Creating an editor with Tracked Changes

Step-by-step guide to setting up a Tiptap editor with the Tracked Changes extension in React.

Learn how to create a fully functional editor with tracked changes, including a toolbar to toggle tracking and accept or reject suggestions.

> **Framework note:**
>
> This guide uses React, but the same concepts apply to Vue and any other framework supported by
> Tiptap.

## Prerequisites

Make sure you have the Tracked Changes extension installed. See the [installation guide](https://tiptap.dev/docs/tracked-changes/getting-started/install.md) for details.

## Set up the editor

Start by creating an editor instance with the `TrackedChanges` extension. You'll want to pass in the current user's ID and metadata so suggestions are attributed correctly.

```jsx
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import { TrackedChanges } from '@tiptap-pro/extension-tracked-changes'

function Editor() {
  const editor = useEditor({
    extensions: [
      StarterKit,
      TrackedChanges.configure({
        enabled: true,
        userId: 'user-123',
        userMetadata: {
          name: 'John Doe',
        },
      }),
    ],
    content: '<p>Start editing to see tracked changes in action.</p>',
  })

  if (!editor) {
    return null
  }

  return <EditorContent editor={editor} />
}
```

At this point, every edit the user makes is tracked as a suggestion. Insertions appear as `add` suggestions and deletions as `delete` suggestions.

## Add a toolbar

Next, add controls to toggle tracking and accept or reject suggestions. The extension provides editor commands for all of these operations.

```jsx
import { useCallback, useState } from 'react'
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import { TrackedChanges } from '@tiptap-pro/extension-tracked-changes'

function Editor() {
  const [isEnabled, setIsEnabled] = useState(true)

  const editor = useEditor({
    extensions: [
      StarterKit,
      TrackedChanges.configure({
        enabled: true,
        userId: 'user-123',
        userMetadata: { name: 'John Doe' },
      }),
    ],
    content: '<p>Start editing to see tracked changes in action.</p>',
  })

  const toggleTrackedChanges = useCallback(() => {
    if (!editor) return
    editor.commands.toggleTrackedChanges()
    setIsEnabled(!isEnabled)
  }, [editor, isEnabled])

  if (!editor) {
    return null
  }

  return (
    <div>
      <div className="toolbar">
        <button onClick={toggleTrackedChanges}>
          {isEnabled ? 'Disable' : 'Enable'} Track Changes
        </button>
        <button onClick={() => editor.commands.acceptAllSuggestions()}>
          Accept All
        </button>
        <button onClick={() => editor.commands.rejectAllSuggestions()}>
          Reject All
        </button>
      </div>
      <EditorContent editor={editor} />
    </div>
  )
}
```

## Add suggestion styles

Suggestions render as `<span>` elements with data attributes. Add CSS to visually distinguish insertions from deletions.

```css
/* Insertions — green highlight */
[data-suggestion-type="add"] {
  background-color: rgba(0, 255, 0, 0.15);
  text-decoration: underline;
}

/* Deletions — red strikethrough */
[data-suggestion-type="delete"] {
  background-color: rgba(255, 0, 0, 0.15);
  text-decoration: line-through;
}

/* Replacement deletions */
[data-suggestion-type="replaceDeletion"] {
  background-color: rgba(255, 0, 0, 0.15);
  text-decoration: line-through;
}

/* Replacement insertions */
[data-suggestion-type="replaceInsertion"] {
  background-color: rgba(0, 255, 0, 0.15);
  text-decoration: underline;
}
```

See the [Styling reference](https://tiptap.dev/docs/tracked-changes/api-reference/styling.md) for all available data attributes.

## Accept and reject at the cursor

You can also accept or reject the suggestion at the current cursor position without passing an ID:

```jsx
<button onClick={() => editor.commands.acceptSuggestion()}>
  Accept at cursor
</button>
<button onClick={() => editor.commands.rejectSuggestion()}>
  Reject at cursor
</button>
```

## Accept and reject in a selection

To accept or reject all suggestions within the current text selection:

```jsx
const acceptInSelection = useCallback(() => {
  if (!editor) return
  const { from, to } = editor.state.selection
  editor.commands.acceptSuggestionsInRange({ from, to })
}, [editor])

const rejectInSelection = useCallback(() => {
  if (!editor) return
  const { from, to } = editor.state.selection
  editor.commands.rejectSuggestionsInRange({ from, to })
}, [editor])
```

## Switch users

In a multi-user application, you'll switch the tracked changes user when the active user changes. Use the `setTrackedChangesUser` command:

```jsx
editor.commands.setTrackedChangesUser({
  userId: 'user-456',
  userMetadata: { name: 'Jane Smith' },
})
```

## Enable code block tracking

By default, code blocks don't support marks. The extension provides a helper to patch any code block extension for tracked changes support:

```jsx
import CodeBlock from '@tiptap/extension-code-block'
import { TrackedChanges, withSuggestionMarkOnCodeBlock } from '@tiptap-pro/extension-tracked-changes'

const TrackableCodeBlock = withSuggestionMarkOnCodeBlock(CodeBlock)

const editor = useEditor({
  extensions: [
    StarterKit.configure({ codeBlock: false }),
    TrackableCodeBlock,
    TrackedChanges.configure({ enabled: true, userId: 'user-123' }),
  ],
})
```

## Next steps

- [Build a suggestion list sidebar](https://tiptap.dev/docs/tracked-changes/guides/suggestion-list.md) to display all suggestions
- Learn about [suggestion grouping and advanced behaviors](https://tiptap.dev/docs/tracked-changes/usage/advanced-usage.md)
- Explore the full [commands API](https://tiptap.dev/docs/tracked-changes/api-reference/commands.md)
