Suggestions

Pro

Inline 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.

4 suggestions to review. Click a highlight to see it.
Our onboarding flow . We it activation, and the .

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Activate your Pro license (once per machine)npx koalaui-cli@latest login <key># Add this component (its dependencies come along)npx koalaui-cli@latest add suggestions

Usage#

This example is part of Koala UI Pro

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.

Grammar: Let's .

Clarity: Let's .

Tone: Let's .

Concise: Let's .

API reference#

Suggestions

The prose container and context for the marks. Forwards all native <div> props; every part accepts className, merged last.

PropTypeDefaultDescription
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.

PropTypeDefaultDescription
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.
labelstring-Badge text in the popover header. Defaults to the category name (Suggestion, Grammar, Clarity or Tone).
reasonstring-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 attributeDescription
data-stateopen or closed, on the mark while it is pending, following its popover.
data-statusapplied or dismissed, on the plain span the mark resolves to (data-slot="suggestion-resolved").
data-settledtrue or false, on the applied-edit morph while it plays; flips to true once the start state has painted.
data-variantThe category, on the applied-edit morph.

FAQ#

The children are the original text the user wrote, and the `suggestion` prop is the replacement. When the user clicks Apply, the children are swapped for the suggestion in place; Dismiss keeps the children.