Skip to content

[iOS Safari] The selection started from the gutter always continues from the start of the content container #255

@oleksandr-danylchenko

Description

@oleksandr-danylchenko

Issue

I faced a pretty specific selection bug/edge case in iOS Safari 👀

Context

Let's consider the following, relatively standard, application structure:

<div class="r60-annotatable no-focus-outline css-iwgmwv" tabindex="-1">
          <div class="r60-span-highlight-layer"></div>
          <main class="contentContainer">
               ...
          </main>          
</div>

The key is that the .r60-annotatable is a grid container that declares the content column. To make the .r60-span-highlight-layer overlap the content, I use the grid-area: content too.

Reproduction

The issue manifests itself when a user starts their selection from the gutter.
Regularly, the selection will continue on the adjacent text to the right of the touch.
However, with the grid container and the .r60-span-highlight-layer overlapping the sibling content element, the selection will continue from the beginning of the content! ⚠️

Case Demo
Regular selection, if the .r60-span-highlight-layer doesn't exist
ScreenRecording_04-22-2026.15-59-01_1.MP4
"Unexpected" selection if the .r60-span-highlight-layer is present as a sibling of the content ⚠️
ScreenRecording_04-22-2026.15-57-01_1.mov

I was able to reproduce the issue in a sandbox - https://codesandbox.io/p/sandbox/safari-grid-overselection-with-overlay-bug-57jrnc (where I made the recordings)

Possible reason of the issue

It didn't make sense initially. Especially as the issue is not reproducible on Android in Chrome. Which means it must be a bug / edge case in Safari's selection handling.

I fed that sandbox with the behavior description into ChatGPT and got the following response (thread source):

So the likely root cause is:

On iOS Safari, selection hit-testing is sometimes using the overlay/grid container box as the drag-start target, even though the overlay has pointer-events: none and user-select: none. Once that happens, WebKit computes the nearest selectable range from the overlay/container boundary, which can collapse to the start/top of the content block.

Suggested solution

Based on those findings, I decided to tweak the position of the .r60-span-highlight-layer in the DOM. And, it worked! 🎉

I tried moving the .r60-span-highlight-layer AFTER the content element sibling. It made the hit-testing work more adequately, using the dimensions of the content instead of the transparent layer! That made it work as if that layer wasn't there, which is exactly what I was hoping for.

ScreenRecording_04-22-2026.15-58-02_1.MP4

Sandbox - https://codesandbox.io/p/sandbox/hardcore-curran-sk4xzp

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions