Selection toolbar
A small toolbar that floats above selected text with quick edits like Improve, Shorten and Translate.
Loading preview…
Install
- 1
Run this command in your Tailwind CSS project. It adds
components/ai/selection-toolbar.tsxand installs its dependencies.$ npx shadcn@latest add https://gradientdeck.com/ai-components/r/selection-toolbar.json
Usage & API
Example
import { SelectionToolbar } from "@/components/ai/selection-toolbar"
<SelectionToolbar
x={1}
y={1}
onAction={() => {}}
/>Props SelectionToolbar
| Prop | Type & description | Required |
|---|---|---|
x | numberPosition relative to the positioned parent: x is the centre, y the top of the selection. | Required |
y | number | Required |
onAction | (action: SelectionAction, question?: string) => void | Required |
pressed | SelectionAction | nullHighlights a button, e.g. while a script drives the demo. | Optional |
Dependencies
- React
- Tailwind CSS
- motion
- lucide-react
Implementation notes
Default is the single floating bar. The four actions are a fixed list, not props, so you cannot add a fifth without editing the file. Labels show from the small breakpoint up. Below that, the title attribute still carries the name and the button's accessible name is the label. Ask replaces the row in place rather than opening a second popover. The preview measures the selection, converts it into the note's coordinate space so a scaled thumbnail still lines up, and clamps x so the bar stays inside the note. It treats the selection as a range of sentences, then runs the canned improve, shorten, or translate for each sentence in that range. The scripted intro selects the middle sentence and fires Improve. A real selection cancels that script. Close on the answer card only clears the answer. It is not a toolbar button.
Choosing a layout
Use it on a document where the person highlights a span and expects a small set of edits, not a blank chat. Improve, Shorten, and Translate cover the common rewrites without a typed instruction. Ask is there when the highlight is a question rather than a replacement: the bar collects the question and your parent answers it beside the text, as the preview does, or however you prefer. Keep the bar mounted only while the selection is inside your editor. The preview listens to selection changes, ignores selections outside the note, and drops the bar if the range collapses, unless the Ask input is focused.
Use Inline prompt when there is no selection and the person invokes an edit on a whole block with a keyboard shortcut. Use Ghost completion when the offer should appear in the caret's path after a pause, with Tab to take it. Use Prose diff when you want the rewrite shown as red deletions and green insertions before anything is committed. The toolbar's Improve path in the preview replaces the sentence outright after a delay. If that is too blunt, take the action id and render Prose diff instead of writing the string through. Version history comes after the edit is in the document. The toolbar does not remember earlier selections.
Why do the words on the buttons disappear?
Under the small breakpoint the labels are display none and the icons remain. The buttons keep their accessible names, Improve, Shorten, Translate, and Ask, and a title tooltip. The preview also reserves a narrower width when it clamps the bar on small screens, so the icon row stays on the selection.
What does Ask do that Improve does not?
Improve, Shorten, and Translate call onAction immediately with the action id. Ask opens an input on the bar. Submitting calls onAction with ask and the trimmed question. Escape from the input goes back to the four buttons and does not call onAction. The preview answers Ask in a card under the paragraph instead of replacing the sentence.