Bug 216681 - iOS: Change events are fired on incorrect elements if a dblclick listener is registered on a parent
Summary: iOS: Change events are fired on incorrect elements if a dblclick listener is ...
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: UI Events (show other bugs)
Version: Safari 13
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2020-09-17 19:42 PDT by Devon Govett
Modified: 2020-09-19 07:14 PDT (History)
9 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Devon Govett 2020-09-17 19:42:41 PDT
In iOS 13 and 14 (have not tested on previous versions of iOS), "change" events (and potentially others) can be fired on an incorrect element if a dblclick listener is registered on a parent element. For example, in a group of checkboxes or radios, tapping quickly between two inputs fires the change event on the first element you tapped twice rather than on the second element. In a group of checkboxes, tapping on one checkbox and then a second should toggle each, but if you do it fast enough, it toggles the first twice instead. This only occurs when a dblclick listener is registered on any parent element above the inputs. It appears that registering the dblclick listener has a side effect of changing the behavior of which element subsequent events after an initial tap are fired on.

Example reproduction: https://fbwry.csb.app/
Source: https://codesandbox.io/s/staging-fog-fbwry?file=/index.html

This manifested in React, which implements event delegation by registering listeners for all known events on a root element, and relies on bubbling to handle events for children. Because of this, there is always a dblclick listener registered at the root of the app, and so this bug is visible even if nothing inside has double click functionality.

Related React issue: https://github.com/facebook/react/issues/19841.

I did a brief search and found this line which looks potentially problematic to me: https://github.com/WebKit/webkit/blob/950143da027e80924b4bb86defa8a3f21fd3fb1e/Source/WebCore/page/ios/FrameIOS.mm#L522. Appears to have been introduced by the patch for this bug: https://bugs.webkit.org/show_bug.cgi?id=197347. I could be completely off though as I haven't worked on Webkit before. ;)
Comment 1 Dan Abramov 2020-09-18 07:47:39 PDT
I want to add that this doesn't only affect the "change" event, but the "click" event itself.

The issue itself also seems scoped to interactive elements like buttons and checkboxes, but does NOT occur for divs with onclick listeners.

Here's a few different repro cases to compare.


## Working Case (Divs)

https://codesandbox.io/s/falling-shape-fjptk?file=/src/index.js (live demo: https://fjptk.csb.app/)

Click A twice.
Expected and actual: click(A), click(A), and dblclick(A). (All good!)

Quickly tap A and then B.
Expected and actual: click(A), click(B). (All good — no double click because target has changed!)

## Broken Case (Checkboxes)

https://codesandbox.io/s/recursing-glade-ysxv2 (live demo: https://ysxv2.csb.app/)

Click A twice.
Expected and actual: click(A), click(A), and dblclick(A). (All good!)

Quickly tap A and then B.
Expected: click(A), click(B).
ACTUAL (broken): click(A), click(A), dblclick(A).

As you can see, here switching from A to B still keeps dispatching events on A, even though the target has changed.

Buttons are broken in the same way as checkboxes.
Comment 2 Dan Abramov 2020-09-18 08:03:59 PDT
It is also curious that the problem seems to go away if the taps have a certain distance between them. E.g. if I decrease the checkbox size via styles I can reproduce it more often. If they are large and I keep them further apart then I struggle to repro.
Comment 3 Radar WebKit Bug Importer 2020-09-18 09:41:19 PDT
<rdar://problem/69156609>