Repository navigation
Shift+click within a rich text block creates a block selection instead of a text selection (regression from #80286) #84576
Description
Description
Since Gutenberg 23.7, shift+clicking inside the same rich text block to extend a text selection results in a block selection instead of a text selection. The native text range stays visible (and typing still replaces it), but the store selection loses its attributeKey/offsets, so RichText is no longer isSelected: the format toolbar disappears and formats like Link (button and Cmd/Ctrl+K) can't be applied to the selected text.
This looks like a regression from #80286 (backported to 7.1 in #80726). (cc @ellatrix @t-hamano)
Analysis
In use-selection-observer.js, every shift+mousedown now marks a multi-selection gesture, regardless of where the click lands:
function onMouseDown( event ) {
isTripleClick = event.detail === 3;
if ( event.shiftKey ) {
startMultiSelect();
}
}While the gesture is in progress, onSelectionChange handles a selection within a single block like this:
const isSingularSelection = startClientId === endClientId;
if ( isSingularSelection ) {
if ( ! isMultiSelecting() ) {
// … selectionChange() with rich text offsets
} else {
multiSelect( startClientId, startClientId );
}
}Both the native selectionchange events fired during the gesture and the final call in onMouseUp (which runs onSelectionChange( event ) before stopMultiSelect()) take the else branch. MULTI_SELECT then stores { selectionStart: { clientId }, selectionEnd: { clientId } } without attributeKey, so RichText is not selected.
Before #80286, shift+click was tracked by the shiftClickInProgress module flag (#79105), which was only read by the block focus handler, so this branch was unaffected. Switching to the shared isMultiSelecting store state made the gesture also affect onSelectionChange.
Note that use-click-selection.js already distinguishes this case explicitly:
if ( event.shiftKey ) {
// When selecting a single block in a document by holding the shift key,
// don't mark this action as multiselection.
if ( startClientId && startClientId !== clickedClientId ) {Why CI didn't catch it
The existing e2e test should properly select part of nested rich text block while holding shift only types after the shift+click and asserts the resulting content. Since the native range is preserved, this still passes. It doesn't assert the store selection or the format toolbar.
Possible fix
Only mark the gesture as a multi-selection when the click lands in a different block than the current selection start, mirroring use-click-selection:
if (
event.shiftKey &&
getBlockSelectionStart() !== getBlockClientId( event.target )
) {
startMultiSelect();
}This would need checking against the nested case the original flag was introduced for (shift+click where the browser focuses a common editable ancestor, e.g. a Group). An e2e test asserting that a shift+click within one paragraph keeps a text selection (e.g. the format toolbar is visible / Cmd/Ctrl+K opens the link UI) would cover the gap.
Step-by-step reproduction instructions
- Add a Paragraph block with some text, e.g. "Hello world, this is a test".
- Click to place the caret before "world".
- Shift+click after "world".
- Observe: the block toolbar shows no formatting controls (Bold, Italic, Link) and Cmd/Ctrl+K does nothing, although "world" appears selected.
- For comparison: select "world" by dragging or with Shift+Arrow. Formatting controls appear and Link works.
Screenshots, screen recording, code snippet
WordPress 7.1:
Shift-clicked, I don't have a Rich Text Selection and can't apply text formatting or links.
WordPress 7.0:
Shift-clicked, text formatting and inline links are available.
Environment info
- WordPress 7.1
- Firefox 157.0b4, Safari 26.5.2
- macOS 26.5.2
Please confirm that you have searched existing issues in the repo.
- Yes
Please confirm that you have tested with all plugins deactivated except Gutenberg.
- Yes
Please confirm which theme type you used for testing.
- Block
- Classic
- Hybrid (e.g. classic with theme.json)
- Not sure
Activity
Block Editor: Preserve rich text selection on Shift+click within the …
Block Editor: Preserve rich text selection on Shift+click within the …