Browser Default Actions

As a rule, events automatically bring certain actions, implemented by the browser.

For example, clicking a link will initiate navigation to its URL or pressing a mouse button over a text, and moving it will select that text, and so on.

Sometimes, while handling events in JavaScript, you don’t want the matching browser action to occur. Instead of that, you want to perform another action. In this chapter, you will learn how to do it.

How to Prevent Browser Actions

It is possible to prevent browser actions in two ways:

  1. The main way is using the event object. There exists a event.preventDefault() method.
  2. In case the handler is assigned with on<event>, false will be returned in the same way.

In the following HTML example, clicking a link will not bring navigation, so browser does nothing:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body>
    <a href="/" onclick="return false">Click here</a>
  </body>
</html>

or

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body>
    <a href="/" onclick="event.preventDefault()">Click here</a>
  </body>
</html>

Usually, the value that is returned by an event handler, is ignored. But, there is an exception: return false from a handler assigned with on<event>. In the rest of the cases return is ignored.

Let’s check out an example of a site menu:

<ul id="menu" class="menu">
      <li><a href="/html">HTML</a></li>
      <li><a href="/css">CSS</a></li>
      <li><a href="/javascript">JavaScript</a></li>
</ul>

The items of the menu are performed as HTML-links <a> rather than buttons. So, in the markup <a> is used. Normally, in JavaScript, developers try to handle clicks. So, the default browser action should be prevented, like in the example below:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body>
    <ul id="menu" class="menu">
      <li><a href="/html">HTML</a></li>
      <li><a href="/css">CSS</a></li>
      <li><a href="/javascript">JavaScript</a></li>
    </ul>
    <script>
      menu.onclick = function(event) {
        if(event.target.nodeName != 'A') {
          return;
        }
        let href = event.target.getAttribute('href');
        alert(href);
        return false; // prevent url change
      };
    </script>
  </body>
</html>

So, for making the menu more flexible, event delegation should be used. You can also add nested listed to them, as well as style them with CSS to slide down.

Passive Handler

On mobile devices, there are events like touchmove that lead to scrolling by default. It can be prevented by applying preventDefault() in the handler. So, anytime a handler detects an event like that, first of all, it performs all the handlers. Afterward, if the preventDefault is not called, it can implement with scrolling. As a consequence, unnecessary delays might happen in UI. The passive: true options inform the browser that the handler will not postpone scrolling.

For several browsers such as Chrome, Firefox by default passive is true for touchmove and touchstart events.

Event.defaultPrevented

This property is true when the browser default action is successfully prevented and false - if not.

At times event.defaultPrevented can be applied for signaling other event handlers that the event has been handled.

Here is an example where a default browser event is prevented:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body>
    <button>Right click show browser context menu</button>
    <button oncontextmenu="alert('Draw menu'); return false">
      Right click show our context menu
    </button>
  </body>
</html>

Then, in addition to the context menu, a document-wide context menu should be implemented:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body>
    <p>Right click for the document context menu</p>
    <button id="elem">Right click the button context menu</button>
    <script>
      elem.oncontextmenu = function(event) {
        event.preventDefault();
        alert("Button context menu");
      };
      document.oncontextmenu = function(event) {
        event.preventDefault();
        alert("Document context menu");
      };
    </script>
  </body>
</html>

The problem is that two menus appear while clicking on elem . They are the button-level and the document-level menu.

A solution to this problem is using event.stopPropagation() like this:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body>
    <p>Right-click for the document menu</p>
    <button id="elem">Right-click for the button menu (fixed with event.stopPropagation)</button>
    <script>
      elem.oncontextmenu = function(event) {
        event.preventDefault();
        event.stopPropagation();
        alert("The button context menu");
      };
      document.oncontextmenu = function(event) {
        event.preventDefault();
        alert("The  document context menu");
      };
    </script>
  </body>
</html>

After running it, the button-level menu will work properly. But, in this case, the access to information about right-clicks for any outer code is denied forever. It is not wise, though.

But, there is an alternative solution: checking in the document handler whether the default action has been prevented or not. Here is how to act:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body>
    <p>Right click on the document menu</p>
    <button id="elem">Right click on the button menu</button>
    <script>
      elem.oncontextmenu = function(event) {
        event.preventDefault();
        alert("The button context menu");
      };
      document.oncontextmenu = function(event) {
        if(event.defaultPrevented) return;
        event.preventDefault();
        alert("The document context menu");
      };
    </script>
  </body>
</html>

So, now everything will work properly.

Also, there exist ways of implementing nested context menus. One way is having a single global object with a handler for document.oncontextmenu. Any right click will be caught by the object. It will look through the stored handlers, running the appropriate one. Then, any piece of code that intends to have a context menu must know about the object, using its help rather than the contextmenu handler.

Summary

All the default actions can be prevented in case you want to handle events exclusively by JavaScript.

So, for preventing a default action, you can use event.preventDefault() or return false. The latter operates only for the handlers that were assigned using on<event>.

In case the default action was prevented, the value of event.defaultPrevented is set true , if not- false.




Do you find this helpful?

Related articles