demo · v150
Workaround Killer
Before v150 the canonical fix for "click handler sees stale selection" was setTimeout(..., 0). This page runs both shapes — plain handler vs. setTimeout-wrapped handler — against the same drag-selection. In Chrome 150+ the plain handler is correct on its own; the setTimeout is dead code.
Drag-select inside the textarea, then release the mouse button. Both panels log what their handler saw at the moment of click.
legacy — setTimeout(..., 0) workaround
modern — plain click handler (v150+)
// Pre-v150 idiom — needed because click ran before mouseup committed selection
input.addEventListener('click', () => {
setTimeout(() => {
const a = input.selectionStart, b = input.selectionEnd;
handle(a, b);
}, 0);
});
// v150+ — the workaround is now redundant
input.addEventListener('click', () => {
const a = input.selectionStart, b = input.selectionEnd;
handle(a, b);
});
why the workaround can go
The selection-update default action of mouseup now runs before the synthesised click dispatches. Click handlers see the committed selection range immediately — no deferred read needed. Codebases that carried the setTimeout(..., 0) dance for over a decade can rip it out; the only downside of leaving it in is that it pushes the work to a separate task, which is a minor latency cost.
see also
- mouseup-before-click — feature index
- Selection Readout — companion demo
- ChromeStatus entry
- mouseup event on MDN
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗