React: Multiple clicks needed for non-anchor element onClick with padding in Safari

Created on 6 Jul 2017  路  11Comments  路  Source: facebook/react

Do you want to request a feature or report a bug?

Bug

What is the current behavior?

In mobile safari and some versions of desktop safari onClick on any non-anchor element requires two click to trigger if

  • the element contains multiple comment/text nodes AND
  • the clicks are on the second or later text nodes AND EITHER

    • the element has padding AND the element is not set to, or natively, display: inline

    • OR the element has display: flex (thanks @malash)

It can be worked around by either

  • not having padding on the element OR
  • ensuring that the element contains only one text node OR
  • adding a single top level element inside the element with the onClick and then having multiple text nodes within that instead, e.g. <span onClick={thing}><span>multi{' '}nodes</span></span> instead of <span onClick={thing}>multi{' '}nodes</span>

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://jsfiddle.net or similar (template: https://jsfiddle.net/84v837e9/).

This can be seen on this fiddle - https://jsfiddle.net/y8Lh8937/

  • First "Yea" is a span with one text node, one click works
  • Second "Yea" is the first text node of a span with padding, one click works
  • "Nah" is the second text node of a span with padding, needs two clicks
  • Third and fourth "Yeah" have the same markup (span with multiple text nodes) but no padding, one click works

Note that you'll need to zoom in to make sure you're hitting the "Nah" on mobile to reproduce the behaviour, as it's sensitive to the exact area hit.

Note that on desktop, to ensure that you're clicking on the text, you should be seeing the text cursor when over the "Nah" items; if you're seeing the default cursor then you're on the <span> (which will work).

What is the expected behavior?

All text nodes should trigger the click handler on the first click.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

Current react
Desktop Safari 10.1.1 (12603.2.4)
Mobile Safari on iOS 10.3.2 (14F89) (use agent 5.0 (iPhone; CPU iPhone OS 10_3_2 like Max OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.0 Mobile/14F89 Safari/602.1)

Thanks to @scottlyttle and @stella-h for this.

Bug

Most helpful comment

@aweary Sorry to get back to this so late. This sounds good. I don't know of any non-trivial way to fix this in a patch to 15, and it's awesome that Safari might have fixed it.

React 16 doesn't wrap text in comments? 馃帀馃帀馃帀 All around.

More 馃帀馃帀馃帀

All 11 comments

Huh. So it does. _Very interesting_. I _think_ this could be because there is a stub onclick handler for interactive elements (like buttons and links) to work around an issue where iOS Safari does not bubble click events:

https://github.com/facebook/react/blob/15.6-dev/src/renderers/dom/client/eventPlugins/SimpleEventPlugin.js#L290-L311

Thanks for the great write up! I want to incorporate this test case into our manual DOM test fixtures. From there, maybe we can identify when this started happening.

I meet the same problem when using flex: https://jsfiddle.net/malash/LpLxjsqe/6/.

Thanks @malash, updated the issue description to indicate that display: flex also triggers it and doesn't require the padding to do so.

Credit to @scottlyttle and @stella-h for tracking this down, I just did the write up.

A temporary fix:

react-issue-10116-fix.jsx

import React from 'react';
import style from './react-issue-10116-fix.css';

export const getComponent = Component => ({ children, ...rest }) => (
  <button
    className={style.button}
  >
    <Component {...rest}>
      {children}
    </Component>
  </button>
)

export const Span = getComponent('span');
// more tags

react-issue-10116-fix.css

.button {
  padding: 0 !important;
  margin: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: transparent !important;
  color: inherit !important;
  font: inherit !important;
  line-height: normal !important;
  overflow: visible !important;
  user-select: none !important;
}

Usage

import { Span } from './path/to/react-issue-10116-fix';

<Span>Hello{', '}world</Span>
// instead of 
// <span>Hello{', '}world</span>

Thanks, our use cases were simple enough that we could always just build up the content inside through string templates instead (although it's a little less readable), so we've been able to work around it that way (second of my suggested workarounds in the initial writeup), but that may be useful for others.

I think this is related to a known webkit bug, described on MDN (MDN provides others pointers about this behavior).

@ghostd that's what we initially thought too, but the problem affects non-mobile safari as well, and most workarounds suggested didn't work (e.g. cursor pointer, adding onclick). IIRC using an <a> _and_ specifying a dummy onClick on the element did work as a workaround did work (@scottlyttle or @stella-h may recall exactly).

Unreal. For me, this is most easy to see/test in Desktop Safari 10.1.1 (thanks @elyobo).

I made a test case outside of React using the same generated markup:
https://codepen.io/nhunzaker/pen/LLoRaX

This... is a very hard bug. It's possible that this is related to how React wraps text content with comments:

<span id="target">
  <!-- react-text: 6 -->Yea,<!-- /react-text -->
  <!-- react-text: 7 -->*******<!-- /react-text -->
  <!-- react-text: 8 -->Nah<!-- /react-text -->
</span>

But that exhausts my knowledge of the problem. This feels like a browser bug that we've stumbled into because of the change made to handle text nodes with comments instead of spans.

I'm unable to reproduce this in Desktop Safari version 10.1.2 on macOS 10.12.6. Maybe the patch release fixed it?

@nhunzaker I think it's likely that the comments are related to the problem. This issue does not occur with React 16, which doesn't wrap text in comments.

Here's a version of the original JSFiddle running the React 16 RC: https://jsfiddle.net/z830gyrj/

I verified on iOS 10.3 that the issue does not occur anymore. Since it's likely a browser bug, I think it's safe to just say that this will be resolved in React 16, since including a fix in a 15.x release is unlikely.

@aweary Sorry to get back to this so late. This sounds good. I don't know of any non-trivial way to fix this in a patch to 15, and it's awesome that Safari might have fixed it.

React 16 doesn't wrap text in comments? 馃帀馃帀馃帀 All around.

More 馃帀馃帀馃帀

Good outcome, thanks all.

Was this page helpful?
0 / 5 - 0 ratings