Blog

JS click event bubbling on iOS

iOS doesn’t do the right thing, and how to fix it.

From Quirksmode way back in 2010:

From the dawn of history browsers have supported event delegation. If you click on an element, the event will bubble all the way up to the document in search of event handlers to execute.

It turns out that Safari on the iPhone does not support event delegation for click events, unless the click takes place on a link or input. That’s an annoying bug, but fortunately there’s a workaround available.

I forgot this bug even existed because FastClick fixes it while removing the 300ms delay that mobile browsers place on taps. Mobile browsers stopped implementing the tap delay (better UX) so FastClick isn’t needed anymore, which is good because it breaks <select> inputs in Chrome 53+ on Android (issue). Bye-bye FastClick.

And the iOS event delegation bug is back.

Raw workarounds

onclick

Adding an onclick event to non-clickable elements allows clicks to bubble fully. I don’t like this approach because any new element being inserted into the DOM requires extra code to support it.

cursor: pointer;

Adding cursor: pointer; to a non-clickable element’s CSS allows clicks to bubble fully. We could create a Sass mixin to encapsulate the code’s purpose, which is easily removable whenever iOS fixes its behavior:

@mixin clickable {
    cursor: pointer;
}

div {
    @include clickable;
}

I don’t like this approach because you have to remember the reason this property is fixing a specific browser bug.

Best approach

Applying the CSS fix to every element for iOS is clean and invisible because there is no cursor on touch devices (for now). This is a nuclear option that relies on user agent detection, but that’s okay in moderation.

.is-ios * {
    cursor: pointer;
}

This snippet relies on a tiny user-agent detection library and some simple JavaScript:

if (gravdept.isIos()) {
    document.querySelector('html').classList.add('is-ios');
}

That’s how I’m handling this going forward.

Demos

I setup two CodePen demos showing the different behavior.

Discourse Gravitated