Skip to content

Shift+click within a rich text block creates a block selection instead of a text selection (regression from #80286) #84576

Closed

Description

@krokodok

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

  1. Add a Paragraph block with some text, e.g. "Hello world, this is a test".
  2. Click to place the caret before "world".
  3. Shift+click after "world".
  4. Observe: the block toolbar shows no formatting controls (Bold, Italic, Link) and Cmd/Ctrl+K does nothing, although "world" appears selected.
  5. 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.

Image

WordPress 7.0:
Shift-clicked, text formatting and inline links are available.

Image

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

  1. added
    [Type] BugAn existing feature does not function as intended
    on Oct 12, 2026
  2. added a commit that references this issue on Oct 12, 2026
    d5818c6
  3. added
    [Feature] Rich TextRelated to the Rich Text component that allows developers to render a contenteditable
    on Oct 13, 2026
  4. added a commit that references this issue on Oct 15, 2026
    fce85c6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    [Feature] Rich TextRelated to the Rich Text component that allows developers to render a contenteditable[Status] In ProgressTracking issues with work in progress[Type] BugAn existing feature does not function as intended

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions