---
title: "Style suggestions with the AI Toolkit"
description: "Apply styles to suggestions with the AI Toolkit."
canonical_url: "https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/agents/review-changes/style-suggestions"
---

# Style suggestions with the AI Toolkit

Apply styles to suggestions with the AI Toolkit.

When the AI makes changes to the document, you can display them as [suggestions](https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/api-reference/suggestions.md) in the editor. In this guide, you'll learn how to customize the suggestions' appearance by modifying their styles and displaying custom elements like menus inside them.

## Add CSS styles to suggestions

When the default `renderDecorations` function is used, the following classes are applied:

- `.tiptap-ai-suggestion`: Applied on the content that is covered by the suggestion range.
- `.tiptap-ai-suggestion--selected`: Applied when the cursor is inside the suggestion range.
- `.tiptap-ai-suggestion--change-group`: Applied when the suggestion is a group of changes instead of a single change.
- `.tiptap-ai-suggestion-sub-change`: Applied on individual sub-changes within a change group.
- `.tiptap-ai-suggestion-diff`: Applied on the diff widget that is displayed next to the suggestion range.
- `.tiptap-ai-suggestion-diff--selected`: Applied to the diff widget when the cursor is inside the suggestion range.
- `.tiptap-ai-suggestion-diff--change-group`: Applied when the diff widget is a group of changes instead of a single change.
- `.tiptap-ai-suggestion-diff-sub-change`: Applied on individual sub-changes within a diff change group.

Use the above classes to style the suggestions, or provide a custom `renderDecorations` function for full control over the UI.

### Example CSS styles

We provide example CSS styles to get you started.

#### Preview mode

Use these styles in [Preview mode](https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/agents/review-changes.md#two-types-of-suggestions), to preview changes before they are inserted into the document.

```css
/* Highlight deleted text in red */
.tiptap-ai-suggestion,
.tiptap-ai-suggestion > * {
  background-color: oklch(80.8% 0.114 19.571);
  color: oklch(0.396 0.141 25.723);
}

/* Lighter background for change groups (sub-changes carry the stronger highlight) */
.tiptap-ai-suggestion.tiptap-ai-suggestion--change-group,
.tiptap-ai-suggestion.tiptap-ai-suggestion--change-group > *:not(.tiptap-ai-suggestion-sub-change) {
  background-color: oklch(0.936 0.032 17.717);
}

/* Highlight sub-changes within inline groups */
.tiptap-ai-suggestion-sub-change {
  background-color: oklch(80.8% 0.114 19.571);
}

/* Highlight inserted text in green */
.tiptap-ai-suggestion-diff,
.tiptap-ai-suggestion-diff > * {
  background-color: oklch(87.1% 0.15 154.449);
}

/* Lighter background for diff change groups (sub-changes carry the stronger highlight) */
.tiptap-ai-suggestion-diff.tiptap-ai-suggestion-diff--change-group,
.tiptap-ai-suggestion-diff.tiptap-ai-suggestion-diff--change-group
  > *:not(.tiptap-ai-suggestion-diff-sub-change) {
  background-color: oklch(0.962 0.044 156.743);
}

/* Highlight sub-changes within the replacement diff widget */
.tiptap-ai-suggestion-diff-sub-change {
  background-color: oklch(87.1% 0.15 154.449);
}

/* Render table row insertions correctly */
.tiptap-ai-suggestion-diff:has(tr) {
  display: contents;
}

.tiptap-ai-suggestion-diff:has(tr) td,
.tiptap-ai-suggestion-diff:has(tr) th {
  background-color: oklch(87.1% 0.15 154.449);
}
```

#### Review mode / Compare documents

Use these styles in [Review mode](https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/agents/review-changes.md#two-types-of-suggestions), to review changes after inserting them in the document.

Also use these styles when displaying suggestions generated by the [Compare Documents](https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/advanced-guides/compare-documents.md) feature.

```css
/* Highlight inserted text in green */
.tiptap-ai-suggestion,
.tiptap-ai-suggestion > * {
  background-color: oklch(87.1% 0.15 154.449);
}

/* Lighter background for change groups (sub-changes carry the stronger highlight) */
.tiptap-ai-suggestion.tiptap-ai-suggestion--change-group,
.tiptap-ai-suggestion.tiptap-ai-suggestion--change-group > *:not(.tiptap-ai-suggestion-sub-change) {
  background-color: oklch(0.962 0.044 156.743);
}

/* Highlight sub-changes within inline groups */
.tiptap-ai-suggestion-sub-change {
  background-color: oklch(87.1% 0.15 154.449);
}

/* Highlight deleted text in red */
.tiptap-ai-suggestion-diff,
.tiptap-ai-suggestion-diff > * {
  background-color: oklch(80.8% 0.114 19.571);
  color: oklch(0.396 0.141 25.723);
}

/* Lighter background for diff change groups (sub-changes carry the stronger highlight) */
.tiptap-ai-suggestion-diff.tiptap-ai-suggestion-diff--change-group,
.tiptap-ai-suggestion-diff.tiptap-ai-suggestion-diff--change-group
  > *:not(.tiptap-ai-suggestion-diff-sub-change) {
  background-color: oklch(0.936 0.032 17.717);
}

/* Highlight sub-changes within the replacement diff widget */
.tiptap-ai-suggestion-diff-sub-change {
  background-color: oklch(80.8% 0.114 19.571);
}

/* Render table row deletions correctly */
.tiptap-ai-suggestion-diff:has(tr) {
  display: contents;
}

.tiptap-ai-suggestion-diff:has(tr) td,
.tiptap-ai-suggestion-diff:has(tr) th {
  background-color: oklch(80.8% 0.114 19.571);
}
```

## Make custom node views read-only in suggestion previews

When a suggestion preview renders custom node views, those node views receive the decorations that mark them as part of an AI Toolkit suggestion. Use `isAiToolkitSuggestionNodeView` to detect that state and disable editing controls inside the node view.

```tsx
import { NodeViewWrapper } from '@tiptap/react'
import { isAiToolkitSuggestionNodeView } from '@tiptap-pro/ai-toolkit'

function MathBlockNodeView({ decorations }) {
  const isAiToolkitSuggestion = isAiToolkitSuggestionNodeView(decorations)

  return (
    <NodeViewWrapper contentEditable={!isAiToolkitSuggestion}>
      {!isAiToolkitSuggestion ? <button>Edit equation</button> : null}
      {/* Render the node view content here. */}
    </NodeViewWrapper>
  )
}
```

## Render React components inside a suggestion

You can use the `renderDecorations` option, combined with [React portals](https://react.dev/reference/react-dom/createPortal), to display a React component inside a suggestion.

First, define a React component with a hook to store the HTML element where the React Portal will be rendered.

```tsx
import { useState } from 'react'

function MyComponent() {
  const [portalElement, setPortalElement] = useState<HTMLElement | null>(null)

  return null
}
```

Then, in the `displayOptions.renderDecorations` option, create a widget decoration with a HTML element that will be used as the entry point of the React portal.

```tsx
const aiToolkit = getAiToolkit(editor)
// Example method of the AI Toolkit that generates suggestions
aiToolkit.executeTool({
  reviewOptions: {
    mode: 'preview',
    displayOptions: {
      renderDecorations({ suggestion, defaultRenderDecorations }) {
        const decorations = defaultRenderDecorations()
        decorations.push(
          Decoration.widget(suggestion.range.to, () => {
            const element = document.createElement('span')
            setPortalElement(element)
            return element
          }),
        )
        return decorations
      },
    },
  },
})
```

Finally, in the React component, render any React elements inside the portal.

```tsx
import { useState } from 'react'
import { createPortal } from 'react-dom'

function MyComponent() {
  const [portalElement, setPortalElement] = useState<HTMLElement | null>(null)

  if (portalElement) {
    return <>{createPortal(<div>Hello, world!</div>, portalElement)}</>
  }
  return null
}
```

## Show a popover or a tooltip when a suggestion is selected

You can use the technique explained above to show a tooltip when a suggestion is selected.

To show a popover when you select a suggestion, you need to use the `getCustomSuggestionDecoration` option. This function allows you to add custom elements to the suggestions, including popovers.

Below is a simplified example on how to do it with the React UI library.

```tsx
import { useState } from 'react'
import { createPortal } from 'react-dom'

// Inside the React component
function MyComponent() {
  const toolkit = getAiToolkit(editor)

  // First, define a hook to store the HTML element where the popover will be rendered
  const [popoverElement, setPopoverElement] = useState<HTMLElement | null>(null)

  // When the tool is executed, configure how the decorations are rendered
  aiToolkit.executeTool({
    reviewOptions: {
      mode: 'preview',
      displayOptions: {
        renderDecorations({ suggestion, defaultRenderDecorations }) {
          const decorations = defaultRenderDecorations()

          // Then, create a Prosemirror decoration that contains the HTML element
          decorations.push(
            Decoration.widget(suggestion.range.to, () => {
              const element = document.createElement('span')

              setPopoverElement(element)
              return element
            }),
          )

          return decorations
        },
      },
    },
  })

  const selectedSuggestion = toolkit.getSelectedSuggestion()

  if (popoverElement && selectedSuggestion) {
    // Then, add the content to the custom element. In this example, we use React Portals to render the popover.
    return <>{createPortal(<Popover suggestion={selectedSuggestion} />, popoverElement)}</>
  }

  return null
}
```

We recommend using the [Floating UI](https://floating-ui.com/) library to display the popover.

When you render the suggestion in the popover, use the `getNextWord` and `getPreviousWord` utility functions to show the previous and next words of the sentence where the suggestion is located.

```ts
import { getNextWord, getPreviousWord } from '@tiptap-pro/ai-toolkit'

// Get the previous word in the sentence.
const { previousWord } = getPreviousWord(editor, suggestion.range.from)
// Get the next word in the sentence and the punctuation mark that follows it, if it's the end of the sentence.
const { nextWord, punctuationMark } = getNextWord(editor, suggestion.range.to)
```

## Display suggestions in a sidebar outside the editor

You can access the current suggestions from the AI Toolkit's `getSuggestions` method.

```ts
const toolkit = getAiToolkit(editor)
const suggestions = toolkit.getSuggestions()
```

Then, you can use this data to render suggestions in the UI, outside the editor. Here is an example of how to do it with the React UI library:

```tsx
// Get the suggestions from the AI Toolkit
const toolkit = getAiToolkit(editor)
const suggestions = toolkit.getSuggestions()

// Render the suggestions in the UI
return (
  <div>
    {suggestions.map((suggestion) => (
      <div key={suggestion.id}>
        <p>Delete: {toolkit.getTextRange(suggestion.range)}</p>
        <p>Add: {suggestion.replacementOptions[0].content.toString()}</p>
      </div>
    ))}
  </div>
)
```

## Next steps

- Learn more about suggestions in the [API reference](https://tiptap.dev/docs/content-ai/capabilities/ai-toolkit/api-reference/suggestions.md). See the `displayOptions` parameter for all the customization options.
