text selection grabbers no longer show on iOS (18.3.1) since 6.35.1 #1538

Open
opened 2025-03-12 12:32:03 +01:00 by jurjanpaul · 18 comments
jurjanpaul commented 2025-03-12 12:32:03 +01:00 (Migrated from github.com)

Describe the issue

I noticed the lack of 'grabbers'/'handles' for my text selections on my iPhone after recently upgrading and could pinpoint the problem to changes in @codemirror/view version 6.35.1; when using 6.35.0 they still show beautifully. Now they have completely disappeared (in all versions after 6.35.0), which makes for a poorer UI.

What I get with @codemirror/view 6.35.1 onwards:
Image

What I got with @codemirror/view 6.35.0 and earlier (and what I think it is supposed to look like):
Image

Browser and platform

mobile Safari on iOS 18.3.1

https://codemirror.net/try/

### Describe the issue I noticed the lack of 'grabbers'/'handles' for my text selections on my iPhone after recently upgrading and could pinpoint the problem to changes in @codemirror/view version 6.35.1; when using 6.35.0 they still show beautifully. Now they have completely disappeared (in all versions after 6.35.0), which makes for a poorer UI. What I get with @codemirror/view 6.35.1 onwards: ![Image](https://github.com/user-attachments/assets/f8b4e079-4dab-405e-aa6c-43f775a1562d) What I got with @codemirror/view 6.35.0 and earlier (and what I think it is supposed to look like): ![Image](https://github.com/user-attachments/assets/226676a5-cd5e-48c0-ad1d-d0e219b78b53) ### Browser and platform mobile Safari on iOS 18.3.1 ### Reproduction link [https://codemirror.net/try/](https://codemirror.net/try/)
marijnh commented 2025-03-13 09:16:45 +01:00 (Migrated from github.com)

It appears that the selection handles are affected by the caret-color style, which we're setting to transparent because we draw our own cursor and don't want the native cursor to interfere.

My initial attempt to handle this was to set it back to initial when there is a non-cursor selection but unfortunately, mobile Safari being the pile of hacks that it is, it appears to only query this style once, when the selection is made (at which point it is still transparent) and then keeps using that color for the lifetime of the non-empty selection, instead of properly querying the current style. This makes it somewhat hard to control this.

I'll see if I can find a kludge, but so far it looks difficult.

It appears that the selection handles are affected by the `caret-color` style, which we're setting to transparent because we draw our own cursor and don't want the native cursor to interfere. My initial attempt to handle this was to set it back to `initial` when there is a non-cursor selection but unfortunately, mobile Safari being the pile of hacks that it is, it appears to only query this style once, when the selection is made (at which point it is still transparent) and then keeps using that color for the lifetime of the non-empty selection, instead of properly querying the _current_ style. This makes it somewhat hard to control this. I'll see if I can find a kludge, but so far it looks difficult.
jurjanpaul commented 2025-03-13 23:03:44 +01:00 (Migrated from github.com)

Ouch. That sounds painful indeed.
Thank you for looking into this and for your explanation of how this came to be and why it is difficult to restore the mobile selection behaviour that I got used to. I would not know where to start finding a solution/workaround either I'm afraid.

Ouch. That sounds painful indeed. Thank you for looking into this and for your explanation of how this came to be and why it is difficult to restore the mobile selection behaviour that I got used to. I would not know where to start finding a solution/workaround either I'm afraid.
lucharlesc commented 2025-03-29 22:10:55 +01:00 (Migrated from github.com)

@marijnh Would a viable solution be to just draw custom cursors on both ends of the range selection? They could be enabled only for mobile Safari and styled to look like the native ones with the circle on top or bottom.

@marijnh Would a viable solution be to just draw custom cursors on both ends of the range selection? They could be enabled only for mobile Safari and styled to look like the native ones with the circle on top or bottom.
lucharlesc commented 2025-03-29 22:32:30 +01:00 (Migrated from github.com)

I think it makes sense to maintain fully custom cursors if using the drawSelection extension, rather than a half custom, half native solution depending on if the selection is a range or not.

I think it makes sense to maintain fully custom cursors if using the `drawSelection` extension, rather than a half custom, half native solution depending on if the selection is a range or not.
ghost commented 2025-06-14 06:55:57 +02:00 (Migrated from github.com)

[](url)
marijnh commented 2025-06-16 10:40:19 +02:00 (Migrated from github.com)

The thing is that, if we draw them as part of the selection layer, which is easy, they'll be clipped off at the edge of the editor by the regular CSS rules and won't be able to stick out of the editor like the native handles would. Also, transparent line backgrounds and such will affect them.

Drawing them as overlays over the editor would be possible, but involve a lot more complexity to ensure they stay properly aligned to the selection.

I'm still half-expecting there to be some undocumented prefixed CSS property that allows us to style these separate from the caret color, but I haven't been able to find such a thing.

The thing is that, if we draw them as part of the selection layer, which is easy, they'll be clipped off at the edge of the editor by the regular CSS rules and won't be able to stick out of the editor like the native handles would. Also, transparent line backgrounds and such will affect them. Drawing them as overlays over the editor would be possible, but involve _a lot_ more complexity to ensure they stay properly aligned to the selection. I'm still half-expecting there to be some undocumented prefixed CSS property that allows us to style these separate from the caret color, but I haven't been able to find such a thing.
chriscoyier commented 2026-02-20 16:24:06 +01:00 (Migrated from github.com)

caret-shape is a brand new thing https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/caret-shape but I don't expect it to be of much help here.

Is there some kind of "force a repaint" strategy we could look at?

`caret-shape` is a brand new thing https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/caret-shape but I don't expect it to be of much help here. Is there some kind of "force a repaint" strategy we could look at?
marijnh commented 2026-02-23 10:25:21 +01:00 (Migrated from github.com)

Is there any situation in which iOS selections do not have selection handles? I know on Android this is a thing, but I couldn't create a situation like that in Mobile Safari.

If not, I guess drawing our own is unproblematic, since these seem to generally be small enough to not stick out of the editor. Attached patch does this (it's in a branch for now). Can anyone think of any issues with this?

Is there any situation in which iOS selections do not have selection handles? I know on Android this is a thing, but I couldn't create a situation like that in Mobile Safari. If not, I guess drawing our own is unproblematic, since these seem to generally be small enough to not stick out of the editor. Attached patch does this (it's in a branch for now). Can anyone think of any issues with this?
shshaw commented 2026-02-23 17:14:59 +01:00 (Migrated from github.com)

I'm not aware of any situations where the drag handles wouldn't be shown. Even on regular text in a page the handles are shown, so readonly instances should also have them (IMO). Not opposed to drawing them within CodeMirorr, though it's nice to use native if it's available.

We were testing our own workaround for this that primarily involved just restoring the caret-color on a hover: none media query. The caret-color: transparent overrides within CM6 seem to be super high precedence & specificity, so I had to force it like this.

Prec.highest(
  EditorView.theme({
    '@media all and (hover:none)': {
      '.cm-content.cm-content, .cm-line.cm-line': {
        caretColor: 'auto !important'
      }
    }
  })
);

The styles could maybe be more targeted to iOS, but does CodeMirror have that kind of detection built into the Theming or would it need to be a ViewPlugin of some sort?

I'm not aware of any situations where the drag handles wouldn't be shown. Even on regular text in a page the handles are shown, so readonly instances should also have them (IMO). Not opposed to drawing them within CodeMirorr, though it's nice to use native if it's available. We were testing our own workaround for this that primarily involved just restoring the `caret-color` on a `hover: none` media query. The `caret-color: transparent` overrides within CM6 seem to be super high precedence & specificity, so I had to force it like this. ``` Prec.highest( EditorView.theme({ '@media all and (hover:none)': { '.cm-content.cm-content, .cm-line.cm-line': { caretColor: 'auto !important' } } }) ); ``` The styles could maybe be more targeted to iOS, but does CodeMirror have that kind of detection built into the Theming or would it need to be a `ViewPlugin` of some sort?
marijnh commented 2026-02-23 17:25:43 +01:00 (Migrated from github.com)

Is hover:none just targeting touch platforms? Unhiding the cursor in general on such platforms is not a good idea, when you're using drawSelection. You'll see two cursors in some situations, and messy overlapping cursors in others.

Is `hover:none` just targeting touch platforms? Unhiding the cursor in general on such platforms is not a good idea, when you're using `drawSelection`. You'll see two cursors in some situations, and messy overlapping cursors in others.
shshaw commented 2026-02-23 18:00:28 +01:00 (Migrated from github.com)

Yes, hover: none is primarily touch devices. I haven't tested multi-cursor with it (not sure how to do that on touch), but it seems to be working as expected.

Yes, `hover: none` is primarily touch devices. I haven't tested multi-cursor with it (not sure how to do that on touch), but it seems to be working as expected.
shshaw commented 2026-03-05 18:30:03 +01:00 (Migrated from github.com)

Is there an easy way to test the changes in github.com/codemirror/view@223fe91207 ? Even on codemirror.net/try or something.

Is there an easy way to test the changes in https://github.com/codemirror/view/commit/223fe912074fd7c7756f6d52797c09a2d1d28570 ? Even on codemirror.net/try or something.
marijnh commented 2026-03-05 18:37:00 +01:00 (Migrated from github.com)

They are in @codemirror/view version 6.39.16

They are in @codemirror/view version 6.39.16
shshaw commented 2026-03-05 18:53:50 +01:00 (Migrated from github.com)

Hm. Doesn't look like the changes from https://github.com/codemirror/view/tree/ios-selection-handles were merged into main for 6.39.16.

Hm. Doesn't look like the changes from https://github.com/codemirror/view/tree/ios-selection-handles were merged into main for 6.39.16.
marijnh commented 2026-03-05 19:06:40 +01:00 (Migrated from github.com)

Oh right, I put it in a branch, sorry. The easiest way to test this would be to clone the repository, check out that branch, build it (npm install), and then copy the files in dist into your project's node_modules/@codemirror/view/dist. Don't just link in the package, since that will also link in its local node_modules.

Oh right, I put it in a branch, sorry. The easiest way to test this would be to clone the repository, check out that branch, build it (`npm install`), and then copy the files in `dist` into your project's `node_modules/@codemirror/view/dist`. Don't just link in the package, since that will also link in its local `node_modules`.
krpano commented 2026-03-05 19:32:59 +01:00 (Migrated from github.com)

Hi, a quick question on these new selection handles for iOS - will it be possible to enable/disable them?
I've also implemented my own iOS selection handles and maybe they might interfere with them...

Hi, a quick question on these new selection handles for iOS - will it be possible to enable/disable them? I've also implemented my own iOS selection handles and maybe they might interfere with them...
marijnh commented 2026-03-09 11:41:31 +01:00 (Migrated from github.com)

I mean, the idea would be that you no longer have to implement your own selection handles. But I guess an option to disable them is easy to add. See attached patch (which is on the main branch now).

I mean, the idea would be that you no longer have to implement your own selection handles. But I guess an option to disable them is easy to add. See attached patch (which is on the main branch now).
krpano commented 2026-03-09 12:24:55 +01:00 (Migrated from github.com)

Great, thanks!
Since I have already implemented them (using ViewPlugin, Decoration and WidgetType) and they are working great and also offering also some specific features (like custom dragging, scroll-control), I want/need to keep them.
My plan was also to release them later as free Codemirror extension.

Great, thanks! Since I have already implemented them (using ViewPlugin, Decoration and WidgetType) and they are working great and also offering also some specific features (like custom dragging, scroll-control), I want/need to keep them. My plan was also to release them later as free Codemirror extension.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
codemirror/dev#1538
No description provided.