Skip to content

Mentions popover crashes block when triggered at line boundary in long paragraphs #75896

@youknowriad

Description

@youknowriad

Description

When typing @ to trigger the mentions autocomplete popover at the right edge of a line in a long paragraph (e.g., at the end of the first line of a wrapping paragraph), the popover position computation throws a JavaScript error that crashes the block and shows the block error boundary.

Steps to reproduce

  1. Create a paragraph block with enough text to wrap across multiple lines.
  2. Place the cursor at the end of the first (or any non-last) line — right at the wrapping boundary.
  3. Type @admin (or just @ followed by any text to trigger the autocomplete).
  4. The block crashes and displays the error boundary ("This block has encountered an error and cannot be previewed").

Expected behavior

The mentions popover should appear correctly positioned near the @ trigger without throwing errors, regardless of cursor position in the paragraph.

Root cause analysis

The issue is in the interaction between getRectangleFromRange and the virtual anchor element created by useAnchor:

  1. getRectangleFromRange (packages/dom/src/dom/get-rectangle-from-range.js, line 90) returns null when a collapsed range produces multiple client rects — which happens at line wrapping boundaries where the browser reports two possible positions for the cursor.

  2. createVirtualAnchorElement (packages/rich-text/src/hook/use-anchor.js, line 91) calls getRectangleFromRange(range) from its getBoundingClientRect() method but does not handle the null return:

getBoundingClientRect() {
    return editableContentElement.contains( range.startContainer )
        ? getRectangleFromRange( range ) // ← can return null
        : editableContentElement.getBoundingClientRect();
}
  1. Floating-UI then calls getBoundingClientRect() on the anchor and attempts to read properties (x, y, width, height) from the null value, causing the crash.

Possible fix

In createVirtualAnchorElement, fall back to editableContentElement.getBoundingClientRect() when getRectangleFromRange returns null:

getBoundingClientRect() {
    if ( ! editableContentElement.contains( range.startContainer ) ) {
        return editableContentElement.getBoundingClientRect();
    }
    return getRectangleFromRange( range ) ?? editableContentElement.getBoundingClientRect();
}

Alternatively, getRectangleFromRange could be made more robust for collapsed ranges at line boundaries — e.g., by picking the first rect when multiple are returned for a collapsed range.

Metadata

Metadata

Assignees

No one assigned

    Labels

    [Feature] UI ComponentsImpacts or related to the UI component system[Type] BugAn existing feature does not function as intended

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions