Suggestions
ProInline AI edit suggestions over a body of text. The AI marks spans with a colored dotted underline; click one to see the proposed replacement and a reason, then apply it in place or dismiss it.
Installation#
Usage#
The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.
Have a license? Unlock it here
Wrap each improvable span in a SuggestionMark with its suggestion (the replacement) and an optional reason. Applying swaps the children for the suggestion in place; dismissing keeps the original. Both fire the root's onApply / onDismiss so you can persist the edit or tick down a counter.
Anatomy#
import { Suggestions, SuggestionMark } from "@/components/ui/suggestions"
<Suggestions>
...
<SuggestionMark suggestion="...">...</SuggestionMark>
...
</Suggestions>Categories#
The variant tints the underline and the popover badge, so a reader can tell a grammar fix from a tone or clarity nudge at a glance: grammar, clarity, tone, and a neutral default.
API reference#
Suggestions
The prose container and context for the marks. Forwards all native <div> props; every part accepts className, merged last.
| Prop | Type | Default | Description |
|---|---|---|---|
| onApply | (suggestion: string, original: string) => void | - | Fires when any mark is applied, with the replacement and the original text. |
| onDismiss | (original: string) => void | - | Fires when any mark is dismissed, with the original text. |
SuggestionMark
One improvable span: a Radix Popover Trigger button whose children are the original text. Forwards all native <button> props except onSelect. Once applied or dismissed it collapses to plain text.
| Prop | Type | Default | Description |
|---|---|---|---|
| suggestion* | string | - | The replacement text swapped in for the children on Apply. |
| variant | "default" | "grammar" | "clarity" | "tone" | "default" | Category: tints the dotted underline, the hover wash and the popover badge. |
| label | string | - | Badge text in the popover header. Defaults to the category name (Suggestion, Grammar, Clarity or Tone). |
| reason | string | - | One-line explanation shown beneath the diff. |
| onApply | (suggestion: string) => void | - | Per-mark apply hook. The root's onApply fires too. |
| onDismiss | () => void | - | Per-mark dismiss hook. The root's onDismiss fires too. |
| Data attribute | Description |
|---|---|
| data-state | open or closed, on the mark while it is pending, following its popover. |
| data-status | applied or dismissed, on the plain span the mark resolves to (data-slot="suggestion-resolved"). |
| data-settled | true or false, on the applied-edit morph while it plays; flips to true once the start state has painted. |
| data-variant | The category, on the applied-edit morph. |