Text in image editPro
Edit the text rendered inside an image: every line a detector found gets a box on the image and a field in a list. Type over a line in place, at its size and angle; the result fades in only inside that line while the others stay editable.
On this page
Installation
Usage
import { TextInImageEdit } from "@/components/ui/chatcn/pro/text-in-image-edit"
<TextInImageEdit
src={image.url}
alt={image.alt}
width={image.width}
height={image.height}
regions={detected.lines}
detecting={detected.pending}
onEdit={async (line, text) => {
const next = await editText(image.id, line.id, text)
return { src: next.url }
}}
/>Each region is one line of lettering: its text, a box in fractions of the image, an optional angle for tilted lines and the cap height, so the inline field opens at the size of the lettering it replaces. onEdit sends one line at a time; resolve with the new image and the component fades it in inside that line's box first, then swaps the full picture with no visible jump. Throw an Error whose message says how to fix the problem, and the line shows it with Retry. Lines can arrive one by one while detecting is on, and status, error and pendingText on a region reflect edits you run yourself.
Examples
States
Props
| Prop | Type | Notes |
|---|---|---|
src, alt | string | The image with the lettering |
width, height, aspectRatio | number | Frame shape before load |
regions | { id, text, box, angle?, fontSize?, label?, dir?, status?, error?, pendingText? }[] | Every line found. box is { x, y, width, height } in fractions of the image |
detecting, detectingLabel | boolean, string | A "Finding text" chip after 300 ms; boxes fade in as lines arrive |
onEdit | (region, text) => Promise<{ src? } | undefined> | Re-render the image with one line changed. Throw to show a failure |
onRegionChange | ({ id, text, original }) => void | After a line's applied text changes |
showBoxes, defaultShowBoxes, onShowBoxesChange | boolean | Outline every line instead of only on hover and focus. Touch screens always outline them |
list | boolean | The list of lines beside or below the image. Default true |
disabled | boolean | Nothing can be edited; boxes lose their outlines |
emptyTitle, emptyDescription, footer | string, ReactNode | The no text state and a slot below |
Keyboard
| Key | Action |
|---|---|
Tab | Moves through the lines on the image, then the fields in the list |
Enter on a line | Opens a field over it with the text selected |
Enter in a field | Applies the new text. Ignored while an input method is composing |
Esc | Cancels: the field closes and focus returns to the line |
Accessibility
- Each box is a button named by the text it holds, "After dark, edit headline", so the name starts with what is visible in the image.
- The list is the full path without a pointer: a labeled field per line with Apply, Retry and Revert buttons whose names start with their visible words.
- Applying, failed and edited are shown with a spinner, an icon and a word, never color alone. Errors are tied to their field and say how to fix the problem.
- Results are announced politely once per line, not while the model works.
- Fields take the line's writing direction, so right to left lettering edits naturally.
Motion
- Boxes fade in over 150 ms as detection finds them. The inline field opens at once: it is triggered by a click or Enter.
- A finished edit fades in over 220 ms inside the line's rotated box only, then the full image swaps underneath with no visible change.
- Nothing moves, so reduced motion keeps the same short fades.