affectUI › Components › Agents
Inline Diff
AI edits to prose shown inline – struck and added words you accept or reject one by one, with keys, a popover and undo.
Part of affectUI Pro. Install: npx shadcn@latest add https://www.affectui.com/r/inline-diff.json · Import from @/components/ui/inline-diff
When to use
- An AI rewrote a piece of prose – an email, a paragraph, a product description – and people should approve each edit
- "Make it shorter", "fix the tone", "fix grammar" actions where most edits are small and scattered through the text
- Review steps in an agent flow where the result should only change with an explicit yes
When not to use
- Code or line-based text – use a line diff with gutters instead
- Full rewrites where almost every word changes – show the new version next to the old one
- Live typing suggestions inside an editor – this reviews a finished suggestion, it isn't a text field
Usage
import { InlineDiff } from "@/components/ui/inline-diff";
export function ReviewRewrite({ draft, rewrite }: { draft: string; rewrite: string }) {
return (
<InlineDiff
label="Suggested by AI · Make it shorter"
original={draft}
suggested={rewrite}
onChange={(text) => saveDraft(text)}
onDone={(text) => setFinal(text)}
/>
);
}Props
| Name | Type | Default | Description |
|---|---|---|---|
original | string | "" | The text as it is now |
suggested | string | "" | The text the AI suggests – diffed word by word against original |
changes | DiffSegment[] | Pre-computed segments ({ type: "equal", text } or { type: "change", remove, insert }) instead of original and suggested | |
onChange | (text: string) => void | Called on every decision and undo with the text so far – pending changes keep the original words | |
onDone | (text: string) => void | Called when the last pending change is decided, with the final text | |
label | string | Small line on the gray tray above the card, e.g. "Suggested by AI · Make it shorter" | |
ref | Ref<InlineDiffHandle> | highlight(index | null), accept(index), reject(index), acceptAll(), rejectAll(), undo(), reset() | |
className | string | Extra class on the root |
Keyboard
- Tab / Shift+Tab: Move between pending changes
- ‹ / ›: Toolbar arrows: highlight the previous / next pending change (wrapping around) and open its popover
- Y / Enter: Accept the focused change and move to the next one
- N / Backspace: Reject the focused change and move to the next one
- Esc: Leave the change or clear the arrow highlight
Accessibility
- Every pending change is a focusable button labelled like "Suggestion 2 of 4: replace “available” with “live”. Press Y to accept, N to reject"
- Removed words are a <del>, new words an <ins>; the side that was dropped is hidden from screen readers once decided
- Each decision, Accept all, Reject all and Undo are announced in a polite live region with the number left
- After the last decision focus moves to Undo, so the keyboard is never stranded; the hidden toolbar is inert
- Popover buttons are labelled and keep focus on the change; visible focus rings throughout
- The prev/next arrows never steal focus: a focused change hands focus to the next one, otherwise the change is highlighted while focus stays on the arrow
- Deleted words are red and struck, added words green – color is never the only cue (strike-through, <del> and <ins>)
Responsive
- Fills its container; the paragraph wraps freely and changes wrap across lines with their tints
- The popover stays inside the card horizontally, down to 320px wide
- Below 400px the prev/next arrows step aside; on touch screens the popover buttons grow and drop the key hints
- Dark mode built in: switches when an ancestor (usually <html>) has the class dark or data-theme="dark"
Requirements
- React 19
Related
- Writing Assistant – AI chat card with a soft gradient glow, suggestions, streaming replies and live voice dictation
- Change Summary – What moved since last time – one metric per row with a colored trend
- Approval Card – An agent asks before it acts – risk badge, preview, Approve and Deny with shortcuts, a pausing countdown, and a smooth morph into a resolved row
Guides
- Human-in-the-loop UI: approvals, permissions and autonomy – UI patterns for keeping people in control of AI agents – approval cards, permission requests, autonomy levels, steering and reviewing changes.