68

I would like to disable the context menu that appears after a long tap (touch and hold) on images in my web application. I've seen posts with different ideas how to do it, but none of them seem to work for me.

Is there a way to do this on Android via HTML/CSS/Javascript?

Janusz
  • 187,060
  • 113
  • 301
  • 369
Roy Sharon
  • 3,488
  • 4
  • 24
  • 34

12 Answers12

181

The context menu has its own event. You just need to catch it and stop it from propagating.

window.oncontextmenu = function(event) {
     event.preventDefault();
     event.stopPropagation();
     return false;
};
bbsimonbb
  • 27,056
  • 15
  • 80
  • 110
  • works! But now I want to block the context menu only on anchor elements. I have the filter working (return false when [a], else true) but returning true doesn't show the dialog. so.. how do you tell the browser it should show? – REJH Oct 31 '16 at 15:34
  • I wouldn't put a filter in the function. It would be better and cleaner to attach the function only to the elements whose context menus you want to disable. – bbsimonbb Oct 31 '16 at 21:56
  • Working on Win10/UWP/MS Edge WebView for Cordova Windows :) – Neptune Systems Oct 25 '17 at 10:24
  • How can you use this in a React Class Component? – KaMZaTa Sep 04 '21 at 15:26
  • 1
    didn't work on firefox android for me. – Flafy Jul 10 '22 at 19:20
  • BE WARNED! This method has a side effect on phones which is the annoying vibration. It makes the device vibrate with every long touch as if contextmenu would show. Vote this comment up for others to be warned as well. – HolyResistance Aug 14 '22 at 20:51
  • @HolyResistance this sounds like a limitation of the method, not a side-effect. If the phone doesn't let you manage the haptic vibration from the browser, that's a limitation, but you should probably try and live with it. The web platform has moved past lots of limitations like this, and it may sort itself out with time. – bbsimonbb Aug 16 '22 at 08:16
41

This should work on 1.6 or later (if I recall correctly). I don't believe there's a workaround for 1.5 or earlier.

<!DOCTYPE html>
<html>
<head>
  <script>
    function absorbEvent_(event) {
      var e = event || window.event;
      e.preventDefault && e.preventDefault();
      e.stopPropagation && e.stopPropagation();
      e.cancelBubble = true;
      e.returnValue = false;
      return false;
    }

    function preventLongPressMenu(node) {
      node.ontouchstart = absorbEvent_;
      node.ontouchmove = absorbEvent_;
      node.ontouchend = absorbEvent_;
      node.ontouchcancel = absorbEvent_;
    }

    function init() {
      preventLongPressMenu(document.getElementById('theimage'));
    }
  </script>
</head>
<body onload="init()">
  <img id="theimage" src="http://www.google.com/logos/arthurboyd2010-hp.jpg" width="400">
</body>
</html>
Roman Nurik
  • 29,665
  • 7
  • 84
  • 82
  • 5
    Not seen anything of the OP since Aug 8th, so I decided to test this myself using the SDK. I tested 1.5, 1.6 and 2.2 and it worked just fine on all of them, so I'm happy to award the bounty now without waiting for the OP to confirm. +1 for a good answer, too. – Andy E Aug 12 '10 at 12:50
  • Roman, thank you very much for your response. I need to test it (not that I disregard Andy's test, but I've seen many things that work fine with the SDK and then fail on the actual devices). I'm sorry for taking so long to respond but I promise to test this before the weekend. Thanks again to both you and Andy! – Roy Sharon Aug 12 '10 at 18:44
  • @Andy -- thanks, @Roy -- sure thing; I tested on a Nexus One, I'd recommend testing on devices with non-standard default Browsers too, @Tegeril -- long time no see! – Roman Nurik Aug 13 '10 at 01:50
  • @Roy: you're welcome to use the test that I set up if you like. http://jsfiddle.net/M7pfy/1/ - the top image should cancel the context menu, the bottom image should allow it. – Andy E Aug 13 '10 at 12:31
  • @Andy -- thanks again! @Roman -- I've tested your solution using Andy's page on two Motorola Blur models. The one with Android 1.5 worked fine, and the one with 2.1-update1 did not work. Damn. I really wanted this to work. Sometimes I wish that the Android world would have been more like the iPhone world, with its single flavor... So what do I do now in terms of stackoverflow customs: Should I mark Roman's solution as an answer or not? I guess that his idea is the way this should be done, but on the other hand it does not solve my problem... Thanks for the advice. – Roy Sharon Aug 15 '10 at 09:27
  • @Roy: that seems really odd, for it to work for me in 1.5, 1.6 and 2.2 but not 2.1 for you. You don't have to accept Roman's answer, although you could accept it and ask another question regarding the problems you're having with the solution. The best idea would be to perform a broader test, if possible - more versions on more devices. Asking another question and providing a link to the example might help here. If it works on other devices, then you know this is the correct solution and the issue is with the device it didn't work on. – Andy E Aug 15 '10 at 09:52
  • 1
    @Andy: Sounds like a good idea. I've accepted Roman's answer, and will try to perform a broader test. If it seems like a device bug, then so be it. If not, I will post another -- more specific -- question. Thanks again for the warm welcome for a newcomer to stackoverflow! – Roy Sharon Aug 15 '10 at 10:12
  • One potential issue I've found with this solution is if the user does any touch command above the image, such as trying to scroll, or zoom, then their command will fail. – Doug S Feb 12 '13 at 18:29
  • 10
    This solution disables all touch events. This could be limiting ! – bbsimonbb Feb 26 '15 at 16:51
  • 8
    Is this really the right answer?. It seems like `img.addEventListener('contetxmenu', function(e) { e.preventDefault(); return false; }, false);` should work no? The solution above will prevent all input. – gman May 18 '15 at 11:50
  • 5
    You see this kind of thing a lot, but you really want to avoid interfering with the propagation of events if you can. A given event can be significant for "your" component as well as others on the page. Eg, a click outside a dropdown may be the queue to roll up the dropdown, as well as whatever action corresponds directly to the click. Find a way that doesn't totally destroy event handling on your page. – bbsimonbb May 18 '15 at 13:52
9

For me, absorbing all the events was not an option since I wanted to disable long press downloads while still allowing the user to zoom and pan on the image. I was able to solve this with css and html only by layering a "shield" div on top of the image like so:

<div class="img-container">
  <div class="shield"></div>
  <img src="img-file.jpg">
</div>

<style>
.img-container { position: relative; }

img { max-width: 100%; }

.shield {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1;
}
</style>

Hope this helps someone!

Brian FitzGerald
  • 3,041
  • 3
  • 28
  • 38
  • You may need to add a `position:relative` to the parent container in order to prevent the parent to take over all the space. This is specially tricky if the parent is a `td` which has a an `ontouchstart` or other interaction event handler linked to it, since you won't visually see that the `td` is taking up all that area. – Daniel F Jan 23 '19 at 13:58
  • Good point, Daniel. I added the `position: relative` css rule. – Brian FitzGerald Jul 31 '22 at 14:31
9

That can be done using CSS:

img {
  pointer-events: none;
}
Artem Andreev
  • 19,942
  • 5
  • 43
  • 42
  • 2
    This doesn't only disable the long tap, but also e.g. the normal tap, so not always an option. – gvlasov May 27 '20 at 01:05
6

It will disable copy, but do not disable selection.

document.oncontextmenu = function() {return false;};

Works in webView.

devasia2112
  • 5,844
  • 6
  • 36
  • 56
5

I use the complete example by Nurik but the the element (an input image in my page) was disable for the click too.

I change the original line by this:

original line:

node.ontouchstart = absorbEvent_;

my change:

node.ontouchstart = node.onclick;

with this approuch i disable the pop-up save image menu on logpress but keep the click event.

I´m testing on a 7" tablet with Android 2.2 under a Dolphin HD browser and works fine!

user229044
  • 232,980
  • 40
  • 330
  • 338
GAL
  • 59
  • 1
  • 1
4

Use this CSS codes for mobile

-webkit-touch-callout: none;
-webkit-user-select: none; /* Disable selection/copy in UIWebView */
vitralyoz
  • 570
  • 7
  • 14
4
pointer-events: none; // for Android

-webkit-touch-callout: none; // for iOS

-webkit-user-select: none; 

-khtml-user-select: none; 

-moz-user-select: none; 

-ms-user-select: none; 

user-select: none;
Viktor Livakivskyi
  • 3,178
  • 1
  • 21
  • 33
soonsuweb
  • 85
  • 4
2

I've had a similar issue. I've tried couple of solution from this thread and another thread for safari on the same problem (Preventing default context menu on longpress / longclick in mobile Safari (iPad / iPhone)) . The bad part was that I couldn't use onTouchStart,onTouchEnd etc...

Only prevent the event from onContextMenu. Snippet from React 16.5.2. Tested in chrome only.

    <img {...props} onContextMenu={event => event.preventDefault()}
    onTouchStart={touchStart}
    onTouchEnd={touchEnd} />

Hope it helps somebody. Cheers!


Vlad Ilie
  • 21
  • 2
0
<a id="moo" href=''> </a>

<script type="text/javascript">
    var moo = document.getElementById('moo');

    function handler(event) {
        event = event || context_menu.event;

        if (event.stopPropagation)
            event.stopPropagation();

        event.cancelBubble = true;
        return false;
    }

    moo.innerHTML = 'right-click here';

    moo.onclick = handler;
    moo.onmousedown = handler;
    moo.onmouseup = handler;
</script>

Capture the onContextMenu event, and return false in the event handler.

You can also capture the click event and check which mouse button fired the event with event.button, in some browsers anyway.

Hare-Krishna
  • 1,425
  • 3
  • 16
  • 26
  • 1
    Sorry, but both of these methods do not work on Android. The oncontextmenu event is never fired, and the click event is not yet fired when the user is touch-holding the element. – Roy Sharon Aug 12 '10 at 18:47
0

Just had a similar problem. The above suggestions did not work for me in the Andoid browser, but I found that displaying the problematic image as a CSS background image rather than an embedded image fixed the problem.

RichardB
  • 2,615
  • 1
  • 11
  • 14
-6

Through raw javascript there are no events that get called for the context menu. Perhaps in the Java world there is something... There are actually several issues regarding javascript events (such as focus not working right) in the Android webkit.

Moncader
  • 3,388
  • 3
  • 22
  • 28
  • Yeah, I agree. Since I've developed a JavaScript library that is going to be used inside a browser, using java is not an option for me. – Roy Sharon Aug 12 '10 at 18:50