iPhone - How to remove text selection magnifier

When running on iPhone after double tap and hold on second tap, default iPhone text selection magnifier pops up. I would like to remove it, but had no luck so far.

Here is what it looks in the app ( bubble in the center of the screen )

Here are links to what it is, I think

What I have tried so far is to change css to this. It did help with some other stuff, but did not solve the magnifier:

-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select:none;
user-select:none;
-o-user-select:none;
-webkit-touch-callout:none;
user-zoom: none;
-webkit-user-drag: none;

i think you may need to use this also…

        -webkit-user-callout: none;

personally i’d wrap all elements with the following and then only apply the opposite settings to the individual elements that would require it, like so…

* {
        -webkit-touch-callout: none;
        -webkit-user-callout: none;
        -webkit-user-select: none;
        -webkit-user-drag: none;
        -webkit-user-modify: none;
        -webkit-highlight: none;
}

You may also have a look at preventDefault, stopPropagation and stopImmediatePropagation.

I have zero experience with iPhone and its loupe, so take my suggestion with a grain of salt.

Unfortunately it’s not working :frowning:
btw here is a test build, if you have an iPhone. Try to double tap few times and hold your finger, it should show up.

https://house-test-threejs.s3.eu-west-2.amazonaws.com/index.html

from a quick flick through some related issues on github it looks like @PavelBoytchev’s suggestion should do it from inside a touchstart event listener but will also prevent any click event listeners from firing, are you using the dblclick event for this?

I don’t use iOS personally so i won’t be able to test, the iPhone 6 i use for testing i’m sure is still on iOS 14 also…

I need to be using regular touch input. Blocking all input is certainly a solution that would work, but not very practical unfortunately.
I am not using anything myself, it’s happening automaticly. I am not even using any touch events/inputs except for orbit controls.

 * {
      touch-action: manipulation;
  }

html - Disable double-tap “zoom” option in browser on touch devices - Stack Overflow

@Lawrence3DPK The idea with double tap event got me thinking and I did use this function to prevent double tap altogether:

This solves it as the double tap is entirely ignored, so thanks for the suggestion. Not sure, if there is some better solution to catching double tap events. Doubleclick event did not work

window.addEventListener(‘dblclick’, ondblclick, false)
function ondblclick(event)
{ event.preventDefault(); }

1 Like

ah ok that’s great, to be fair i didn’t even think about the dblclick event not being supported by mobile devices, i just read that it’s not here so if your workaround works it works :ok_hand:

So it’s actually still there, it’s just happens less often. Anyways, if you would have some other idea or anyone else, let me know. But thanks for the help.

I think you’ve correctly identified the moment you’d like to intercept the event and precent them. But on recent mobile devices, you’ll need to pass a third parameter into the event listener to say that the event is not passive. Like so:

document.body.addEventListener('touchend', detectDoubleTapClosure(), { passive: false });

More info here: DOM Standard

Update: Mar 28, 2023
Actually, upon further inspecting your gist, you’re not really gaining any advantage from the setTimeout. I’ve re-written it here:

function createHandler(func, timeout) {

  let timer = null;
  let pressed = false;

  return function() {

    if (timer) {
      clearTimeout(timer);
    }

    if (pressed) {
      if (func) {
        func.apply(this, arguments);
      }
      clear();
    } else {
      pressed = true;
      setTimeout(clear, timeout || 500);
    }

  };

  function clear() {
    timeout = null;
    pressed = false;
  }

}

// ....
// And you would use it like this:

const ignore = createHandler((e) => e.preventDefault(), 500);
document.body.addEventListener('touchstart', ignore, { passive: false });

For Mobile Safari, the actions go like this:

  1. touchstart
  2. touchend Release quickly
  3. touchstart Second one to hold
  4. Magnifying glass comes up

So, if you want to capture the magnifying glass pick up, you need to intercept that second touchstart — not the end or cancel event.

Good luck!

3 Likes

Big thanks to @jonobr1 for the code. I made a my own variation that is in Typescript and specialized only for TouchEvents.

Seems to work fine with mobile Safari. Zoom and text selection is disabled and “click” events are still triggered on simple taps.

function createDoubleTapPreventer(timeout_ms: number) {
    let dblTapTimer = 0;
    let dblTapPressed = false;

    return function (e: TouchEvent) {
        clearTimeout(dblTapTimer);
        if (dblTapPressed) {
            e.preventDefault();
            dblTapPressed = false;
        } else {
            dblTapPressed = true;
            dblTapTimer = setTimeout(() => {
                dblTapPressed = false;
            }, timeout_ms);
        }
    };
}

document.body.addEventListener("touchstart", createDoubleTapPreventer(500), { passive: false });

It was great, it saved my life