Selection toolbar
Selection toolbar is a small floating toolbar that appears over text a person selects, with actions such as Add to notes and Ask AI Tutor. Use it on lesson and answer text.
Beta until design confirms the code-only parts (one button holding icon and text, the 8px gap from the selection, the Alt+F10 shortcut and its spoken hint, below-the-selection placement on touch) and it is tested with VoiceOver, NVDA, TalkBack and iOS long-press selection.
Preview
Select text in the lesson with a mouse, a finger or the keyboard. Change the controls to try each option.
Chapter 2 · Business structures
A sole trader owns the business alone. They make every decision, keep the profit and are personally liable for its debts.
A company is its own legal person. Shareholders agree its plan, and their risk is limited to what they invested.
Select some lesson text to show the toolbar.
<article ref={lessonRef}>…lesson text…</article>
<SelectionToolbar
container={lessonRef}
onAddToNotes={(text) => addNote(text)}
onAskAI={(text) => askTutor(text)}
/>Installation
Availability
@nuton/ui and @nuton/tokens are private workspace packages and aren't published yet (D4, D12). Inside the Nuton monorepo, add them as workspace dependencies.
pnpm add @nuton/ui @nuton/tokensnpm install @nuton/ui @nuton/tokensyarn add @nuton/ui @nuton/tokensimport '@nuton/tokens/tokens.css'
import '@nuton/ui/styles.css'Usage
import { SelectionToolbar } from '@nuton/ui'
const lessonRef = useRef<HTMLElement>(null)
<article ref={lessonRef}>{lesson}</article>
<SelectionToolbar
container={lessonRef}
onAddToNotes={(text) => saveNote(text)}
onAskAI={(text) => openTutorWith(text)}
/>- Put
SelectionToolbarnext to the text and pass the text's element (or a ref) ascontainer. It shows only for selections that start and end inside it. onAddToNotesandonAskAIadd the two standard actions. For anything else, passactions: each has alabel, an optional Remixicon,onSelect(text, selection)and an optionalconfirmationto announce.- The toolbar closes after an action and clears the selection. If the action opens something, such as the AI Tutor composer, move focus there in
onSelect. - Keep it to two or three short actions. It sits over the text people are reading.
- Give keyboard users another route to the same actions too, such as an “Ask about this passage” button: selecting static text with a keyboard needs caret browsing (F7).
Variants and sizes
Actions
The default pair or one action. For your own set (the Preview playground has “study actions”), pass actions.
<SelectionToolbar container={ref} onAddToNotes={addNote} onAskAI={askTutor} />
<SelectionToolbar container={ref} onAddToNotes={addNote} />Placement
auto (default) puts the toolbar above the first line of the selection, as in Figma. After a touch selection it goes below the last line, so the phone's own copy menu (which sits above) stays visible. It flips side when there is no room, stays 12px inside the viewport and follows scrolling and resizing. Force a side with placement="above" or "below".
Measurements
| Part | Value | Source |
|---|---|---|
| Toolbar | 32 tall, padding 2, gap 2, radius 8, Bg/White, 1px Stroke/Soft-200, regular-shadow/x-small | Figma Rich Editor [1.1] (TextEditorToolbar) |
| Action | 28 tall, radius 6, Label/Small, Text/Sub-600; hover Bg/Weak-50 | Figma Rich Editor Items [1.1] |
| Action padding | 4 before the icon, 10 after the text; icon 20, 6 to the text | Code-only (Figma draws the + and the text as two items) |
| Gap from the selection | 8 (--nu-selection-toolbar-offset) | Code-only (live uses 14) |
| Viewport margin | 12 (--nu-selection-toolbar-margin) | Live app |
States and interactions
Component tokens
Set on .nu-selection-toolbar. Colours come from the Text editor toolbar tokens (--nu-text-editor-toolbar-bg, --nu-text-editor-item-*).
| Token | Value | Used for |
|---|---|---|
--nu-selection-toolbar-offset | space-2 (8) | Gap between the selection and the toolbar |
--nu-selection-toolbar-margin | space-3 (12) | Minimum distance from the viewport edges |
Composition examples
Save highlights to notes
Select text and choose Add to notes. The note appears in the list and “Added to notes” is announced.
Inside a scrolling area
The toolbar follows the selection while the area scrolls, and hides while the selection is scrolled out of sight.
With the AI Tutor
In Chat, Ask AI Tutor fills the composer's “Asking about” card (ChatContextCard) and moves focus to the composer. Inside a Modal or Sheet, pass the dialog element as portalContainer so the toolbar stays inside its focus trap.
API reference
SelectionToolbar props
| Prop | Type | Default | Description |
|---|---|---|---|
containerrequired | RefObject<HTMLElement | null> | HTMLElement | null | — | The element whose text can be selected. Selections must start and end inside it. |
actions | SelectionToolbarAction[] | — | Each: id, label, icon?, onSelect(text, selection), confirmation?, disabled?, group?. Replaces the two default actions. |
prompt | SelectionToolbarPrompt | — | Menu layout only: a text box above the actions for describing a change in your own words. placeholder, onSubmit(text, selection), label?, send?, defaultValue?. Enter or the send button submits and closes the menu; the box keeps focus without losing the selection. Code-only (C106). |
layout | 'toolbar' | 'menu' | 'menu' | menu (the default, as used in the lesson and research) shows a compact vertical menu with the actions grouped under headings (action.group), for many actions such as quick AI actions followed by notes. toolbar is the older single-row bar. Up and Down move between items; Home and End jump; Escape closes. Code-only (C101). |
onAddToNotes | (text, selection) => void | — | Adds "Add to notes" (with the "Added to notes" confirmation). Ignored when actions is set. |
onAskAI | (text, selection) => void | — | Adds "Ask AI Tutor". Ignored when actions is set. |
placement | 'auto' | 'above' | 'below' | 'auto' | Above the selection; below it after a touch selection. Flips when there is no room. |
shortcut | SelectionToolbarShortcut | false | { key: 'F10', altKey: true } | The key that moves focus into the toolbar. Change labels.available to match. false turns it off. |
clearSelectionOnAction | boolean | true | Clears the text selection after an action. |
minLength · maxLength | number | 1 · none | Selections shorter or longer than these (in characters) show no toolbar. |
announce | boolean | true | Puts the shortcut hint and confirmations in a polite status region. |
disabled | boolean | false | Turns the toolbar off. |
onOpenChange | (open: boolean) => void | — | Called when the toolbar appears or hides. |
portalContainer | HTMLElement | null | document.body | Where the toolbar is rendered. Use the dialog element inside a Modal or Sheet. |
labels | Partial<SelectionToolbarLabels> | SELECTION_TOOLBAR_LABELS | toolbar (“Selected text actions”), addToNotes, addedToNotes, askAI (“Ask AI Tutor”), available (the spoken shortcut hint). An empty string turns a message off. |
className · …div props | HTMLAttributes<HTMLDivElement> | — | Go to the toolbar element; the ref points at it while it is shown. |
The selection argument has text, a copy of the range, its rect and the container.
Accessibility
Keyboard
| Key | Behaviour |
|---|---|
| Alt / F10 | With text selected, moves focus into the toolbar (Option+F10 on a Mac) |
| ← / → | Moves between actions; Home and End jump to the first and last |
| Enter / Space | Runs the action |
| Esc | Closes the toolbar. From inside it, focus and the selection go back to the text |
| Tab | From inside the toolbar: closes it and returns to the text |
Screen readers
A toolbar named “Selected text actions” with buttons named by their visible text. When it appears, “Actions for the selected text are available. Press Alt+F10 to reach them.” is announced politely, once. Confirmations such as “Added to notes” are announced politely after the action.
Focus
The toolbar never takes focus by itself, so selecting text never interrupts reading. After an action, focus goes where the action puts it; if it puts it nowhere, focus returns to the text.
Contrast and colour
Action text and icons Sub-600 on white (6.69:1); hover Weak-50. In forced-colours mode the toolbar keeps a CanvasText outline and focus shows as a Highlight outline.
Touch and pointer
Actions are 28px tall (WCAG 2.5.8). After a long-press selection the toolbar sits below the text, so it doesn't cover the phone's own menu; it doesn't block that menu or the selection handles. Clicking an action keeps the selection. The fade stops with reduced motion.
You must: name the actions clearly, move focus in actions that open something, give keyboard users another route to the same actions, and set portalContainer inside dialogs.
Figma mapping
| Figma | Code |
|---|---|
| Rich Editor [1.1] over selected text (575:19715) | SelectionToolbar (built on TextEditorToolbar) |
| Rich Editor Items: + icon and “Add to Notes” text | One action button with icon and text, label “Add to notes” (sentence case) |
| No “Ask AI Tutor” item | onAskAI (code-only; the live app has “Ask Nuton”) |
Guidelines and related components
Use a selection toolbar for
- Saving or asking about part of a lesson or answer
- Quick actions on text people are reading
Don't use it for
- Formatting text people are editing (use Text editor)
- Actions that need no selection (use Button)
- Long menus (use Dropdown menu)
Do and don't
Added to notes
Are you sure you want to add this to your notes? OK / Cancel