> ## Documentation Index
> Fetch the complete documentation index at: https://superdoc-caio-pizzol-docs-ai-core-preset.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom track changes UI

> Build your own track-changes review panel. Accept, reject, navigate next and previous.

`useSuperDocTrackChanges()` exposes the live tracked-change list in document order. Accept, reject, accept-all, reject-all, scroll-to, and next / previous navigation route through `editor.doc.trackChanges.*` underneath.

## A live list of changes

```tsx theme={null}
import { useSuperDocTrackChanges, useSuperDocUI } from 'superdoc/ui/react';

export function ReviewPanel() {
  const { items, total, authors } = useSuperDocTrackChanges();
  const ui = useSuperDocUI();

  return (
    <aside>
      <h2>Track changes · {total}</h2>
      <div>
        {authors.map((author) => (
          <span key={`${author.email ?? ''}:${author.name ?? ''}`}>
            <span style={{ background: author.color }} />
            {author.name ?? author.email}
          </span>
        ))}
      </div>
      {items.map((item) => (
        <ChangeRow
          key={item.id}
          change={item.change}
          authorColor={item.authorColor}
          onAccept={() => ui?.trackChanges.accept(item.id)}
          onReject={() => ui?.trackChanges.reject(item.id)}
        />
      ))}
    </aside>
  );
}
```

`items` mirrors `editor.doc.trackChanges.list()`. Each item carries `id` plus the full `change` record (type, author, excerpt, address). If you configure `modules.trackChanges.authorColors`, each item also exposes `authorColor`, and `authors` contains the unique authors in document order with their resolved colors.

## Per-author colors

Use `modules.trackChanges.authorColors` when your review UI needs a stable legend or when imported DOCX files can contain authors your app did not know ahead of time.

```tsx theme={null}
<SuperDocEditor
  document="/contract.docx"
  modules={{
    trackChanges: {
      visible: true,
      authorColors: {
        overrides: {
          'alice@example.com': '#1f6feb',
          'Bob Reviewer': '#d1242f',
        },
        resolve: (author) => {
          if (author.email?.endsWith('@outside-counsel.com')) return '#8250df';
          return undefined;
        },
      },
    },
  }}
  hideToolbar
  contained
  onReady={({ superdoc }) => setSuperDoc(superdoc)}
/>
```

SuperDoc uses the same resolver for the rendered document and the UI snapshot. That keeps custom cards, author legends, and document highlights in sync without app-side CSS selectors.

## Accept and reject

```tsx theme={null}
ui.trackChanges.accept(changeId);
ui.trackChanges.reject(changeId);
ui.trackChanges.acceptAll();
ui.trackChanges.rejectAll();
```

All four return Document API receipts. After a single decision, the change leaves the live list (it's been applied or discarded). To render an audit trail, snapshot the change before deciding:

```tsx theme={null}
const decideChange = (id: string, decision: 'accepted' | 'rejected') => {
  const item = trackChanges.items.find((it) => it.id === id);
  const snapshot = item?.change ?? null;

  if (decision === 'accepted') ui.trackChanges.accept(id);
  else ui.trackChanges.reject(id);

  if (snapshot) {
    setDecided((prev) => [...prev, { id, decision, snapshot }]);
  }
};
```

## Navigate

```tsx theme={null}
const nextId = ui.trackChanges.next();
const prevId = ui.trackChanges.previous();
ui.trackChanges.scrollTo(changeId);
```

`next` and `previous` walk the list in document order. They wrap. `scrollTo` scrolls the editor viewport to the change's anchor and sets it as the active id.

## Independent vs paired replacements

A typed-over selection in Suggest mode produces an insertion AND a deletion. Default `'paired'` mode collapses them into one tracked-change entity (accept once, both apply). Independent mode gives each half its own id.

```tsx theme={null}
<SuperDocEditor
  document="/contract.docx"
  modules={{ trackChanges: { replacements: 'independent' } }}
  hideToolbar
  contained
  onReady={({ superdoc }) => setSuperDoc(superdoc)}
/>
```

Pick what your review UI wants to render. One row per replacement (paired) or two rows for the deletion + insertion (independent).

## Highlight the active card

The selection slice exposes `activeChangeIds`. Use it to highlight the card matching the cursor.

```tsx theme={null}
import { useSuperDocTrackChanges, useSuperDocSelection } from 'superdoc/ui/react';

function ActiveAwareList() {
  const { items } = useSuperDocTrackChanges();
  const selection = useSuperDocSelection();
  const activeId = selection.activeChangeIds[0] ?? null;

  return items.map((item) => (
    <div key={item.id} className={item.id === activeId ? 'active' : ''}>
      {/* row */}
    </div>
  ));
}
```

## What the snapshot looks like

| Field      | Type                   | Meaning                                                                                                                                       |
| ---------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `items`    | `TrackChangesItem[]`   | Tracked changes in document order.                                                                                                            |
| `total`    | `number`               | Convenience count of `items.length`.                                                                                                          |
| `activeId` | `string \| null`       | Active change driven by selection or by `next / previous / scrollTo`.                                                                         |
| `authors`  | `TrackChangesAuthor[]` | Unique tracked-change authors in document order. Present with resolved `color` values when `modules.trackChanges.authorColors` is configured. |

`TrackChangesItem` is `{ id, change, authorColor? }`. The `change` shape mirrors `editor.doc.trackChanges.list()`: `type`, `author`, `authorEmail`, `excerpt`, `address`, etc. When author colors are configured, `change.authorColor` mirrors `item.authorColor`.

## Theming

Insertion, deletion, and format-change highlights are themable via `--sd-tracked-changes-*` CSS variables (`--sd-tracked-changes-insert-background`, `--sd-tracked-changes-delete-border`, etc.). Per-author colors set those variables on the rendered tracked-change element. See [Theming overview](/editor/theming/overview) and [Custom themes](/editor/theming/custom-themes) for the full token list.

## Trade-offs

* `acceptAll` and `rejectAll` apply across every story. To scope to body only, call `accept` / `reject` per id.
* Tracked changes in headers, footers, and footnotes route correctly through `scrollTo`. Non-body entities snap to view (story activation mounts the surface synchronously before alignment); body entities scroll smoothly.
* The merged Activity feed pattern is consumer-owned. The controller stays minimal so apps that only render tracked changes don't pay for comment merging, and apps that want an Activity panel decide their own ordering rules.
