Repository navigation
[iOS] Caret: A press just above the caret drags it and draws a gesture at the same time #6061
Description
Seen in Safari on iOS 27, on an iPhone, while testing #5903. Not yet checked on main. The press has to land just outside the area that counts as the caret, so it can take several tries.
Steps to Reproduce
- N
- Tap
Nto edit it, placing the caret at the end of the text. - Press just above the caret, about 7px above its top edge and 3px to its left.
- Immediately start dragging.
Current Behavior
The caret moves to the start of N while the gesture is recognized. The debug log records the swipes ↓↑↓↑↓→↑ (#281 to #287) and a completed, unabandoned gesture (#289), and the next touch finds the caret at the start of the text (#293).
Expected Behavior
In this case
The caret should follow the finger, and drags should not be recognized as a gesture: no trace, no Gesture Menu, and no command.
In general
A touch that iOS uses to drag the caret should never also be tracked as a gesture. A touch that starts on the caret but moves before iOS raises the magnifier should not draw a gesture or scroll the document. Sometimes, iOS does not perform the caret drag if it begins within 75-80ms of the touchstart, but this is typically the result of frenzied testing. In the real world, I would expect to see this as the result of an accidental brush or something spilled on the phone rather than an intentional user action. Therefore, performing no action seems safest.
A touch that starts away from the caret should still draw a gesture as usual.
Debug Log
--- device: iPhone (web), 390x844, touch
--- userAgent: Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/27.0.1 Mobile/15E148 Safari/604.1
--- commit: f8305ed32f
22:38:58.805 +693ms #276 touchstart {"x":86,"y":169}
22:38:58.826 +21ms #277 touchCaret {"x":89,"y":176,"height":20,"editableLeft":72,"editableTop":170,"editableRight":120,"editableBottom":200}
22:38:58.970 +81ms #279 longPressEnd {"eventType":null,"dragHold":false}
22:38:58.975 +5ms #280 action longPress {"value":"Inactive"}
22:38:58.987 +12ms #281 swipe {"dir":"d","sequence":"d"}
22:38:59.121 +134ms #282 swipe {"dir":"u","sequence":"du"}
22:38:59.271 +151ms #283 swipe {"dir":"d","sequence":"dud"}
22:38:59.455 +184ms #284 swipe {"dir":"u","sequence":"dudu"}
22:38:59.623 +167ms #285 swipe {"dir":"d","sequence":"dudud"}
22:38:59.773 +150ms #286 swipe {"dir":"r","sequence":"dududr"}
22:38:59.790 +18ms #287 swipe {"dir":"u","sequence":"dududru"}
22:38:59.924 +133ms #288 tap {"eventType":"touchend","cancelable":true,"touching":true,"editingOrOnCursor":true,"isVisible":true,"longPress":"Inactive","touchMoved":true,"isKeyboardOpen":true,"noteFocus":false,"cursorOffset":1,"activeElement":"editable-d93395938d"}
22:38:59.924 +0ms #289 gesture {"sequence":"dududru","x":86,"y":169,"endX":169,"endY":167,"abandon":false,"innerHeight":699,"safeAreaBottom":0}
22:38:59.927 +3ms #290 touchend {"x":169,"y":167,"moves":57}
22:39:00.993 +1052ms #293 touchstart {"x":91,"y":175}
22:39:01.017 +24ms #294 touchCaret {"x":77,"y":176,"height":20,"editableLeft":72,"editableTop":170,"editableRight":120,"editableBottom":200}
Activity