All hooks / Events and input
useTextSelection
The text the user has selected inside an element, or null. Returns a callback ref for the element.
Follows mouse, touch, and keyboard selection (Shift+arrows, select all). While the mouse or finger is still down it waits, so a toolbar doesn't flicker during a drag, and updates on release. null when the selection is empty, only whitespace, or not entirely inside the element.
Import
import { useTextSelection } from '@vincent.ri/react-tils'
// or only this hook
import { useTextSelection } from '@vincent.ri/react-tils/useTextSelection'Usage
const [ref, selection] = useTextSelection<HTMLElement>()
return (
<>
<article ref={ref}>{children}</article>
{selection && (
<div style={{ position: 'fixed', top: selection.rect.top - 40, left: selection.rect.left }}>
<button onClick={() => quote(selection.text)}>Quote</button>
</div>
)}
</>
)Live demo
Select some text with the mouse or keyboard.
Hooks for browser state that render the right first frame. Double-click anything here.
When to use it
A floating toolbar for highlight, comment, share quote, or "Ask AI about this", or a "copy quote" button.
When not to
The text is in an <input> or <textarea>; read its selectionStart and selectionEnd. For a rich text editor, use the editor's own selection API. rect doesn't follow scrolling; read range.getBoundingClientRect() again if the page scrolls.
API
function useTextSelection<T extends Element = HTMLElement>(): [(element: T | null) => void, TextSelection | null]Returns [ref, selection]. Pass ref to the element containing the text.
Types
export type TextSelection = {
/** The selected text. */
text: string;
/** Where the selection is on screen, in viewport coordinates, for placing a toolbar. */
rect: DOMRect;
/** A copy of the selected range, e.g. to wrap it in a highlight. */
range: Range;
};Browser support
| Uses | Chrome | Edge | Firefox | Safari | Chrome Android | Safari iOS |
|---|---|---|---|---|---|---|
| Pointer eventsWidely available | 55+ | 12+ | 59+ | 13+ | 55+ | 13+ |
| getSelectionWidely available | 1+ | 12+ | 1+ | 1+ | 18+ | 1+ |
| selectionchange eventWidely available | 11+ | 12+ | 52+ | 5.1+ | 18+ | 5+ |
First version with support, from MDN's compatibility data (web-features 3.42.0, @mdn/browser-compat-data 8.1.5).