Focusing: focus/blur

Focusing on an element generally considers “preparing to accept the data here”. So, it’s the moment that one can run the code to initialize the required functionality.

An element receives a focus at the moment the user clicks on it or presses the keyboard Tab key.

Also, an HTML autofocus can be used: it puts the focus into an element by default during the loading of the page.

The moment of losing the focus is more principal. It happens when the user clicks somewhere else or presses the Tab key for going to the next form field. Of course, other means exist, as well.

So, to lose the focus means that the data has been inserted, and the code can be run to check it, to save it on the server, and more.

There are significant peculiarities while dealing with focus events that we are going to cover further on.

Events:focus/blur

On focusing, the focus event is called, and when the element loses the focus, the blur event is called.

To be more accurate, let’s apply them for validation of an input field.

  • The blur handler checks if the email is entered. If it’s not entered- an error occurs.
  • The focus handler hides the error message:
<!DOCTYPE HTML> 
<html>
  <head>
    <style>
      .invalid { border-color: red; }
      #error { color: red }
    </style>
  </head>
  <body>
    <div id="error"></div>
    Your email please: <input type="email" id="input">
    <script>
      input.onblur = function() {
        if (!input.value.includes('@')) { // not email
          input.classList.add('invalid');
          error.innerHTML = 'Please write a correct email.'
        }
      };      
      input.onfocus = function() {
        if (this.classList.contains('invalid')) {
         // remove the "error" indication, if the user wants to re-enter something
          this.classList.remove('invalid');
          error.innerHTML = "";
        }
      };
    </script>
  </body>
</html>

Modern HTML is capable of doing much validation, applying input attributes: required, pattern, and more. JavaScript may be used for getting more flexibility. Also, the changed value can be sent to the server, in case it’s correct.

Methods focus/blur

The elem.focus() and elem.blur() methods are used for setting/unsetting the focus on the element.

Let’s make the user unable to leave the input, if the value is invalid, like this:

<!DOCTYPE HTML> 
<html>
  <head>
    <style>
      .errorClass {
      border-color: red;
      }
    </style>
  </head>
  <body>
    <div>
      Your email please: <input type="email" id="input">
      <input type="text" placeholder="invalidate the email and try to focus here">
    </div>
    <script>
      input.onblur = function() {
        if (!this.value.includes('@')) { // not email
          // show the error
          this.classList.add("errorClass");
          // ...and put the focus back
          input.focus();
        } else {
          this.classList.remove("errorClass");
        }
      };
    </script>
  </body>
</html>

It operates on all the browsers, except for Firefox (bug).

If you enter something into the input and then try to apply Tab or click away from the <input>, and then onblur brings the focus back.

Another important note: it’s not possible to prevent losing focus by calling event.preventDefault() in onblur, as the latter works the element lost the focus. A focus loss can happen for different reasons.

One of the reasons is when the user clicks somewhere else. But, JavaScript itself can lead to it, for example:

  • An alert moves the focus to itself, causing the focus loss at the element ( it’s a blur event). When the alert is discarded, the focus returns (focus event).
  • In case an element is removed from DOM, it may also cause a focus loss. But, if it is reinserted later, the focus won’t return.

The features above sometimes cause focus/blus handlers to misbehave: they trigger when it’s not necessary.

The best solution is to be careful while using those events.

Allow Focusing on any Element: tabindex

Focusing is not supported by many elements by default.

The list can vary a little between browsers, but a thing is constantly correct: focus/blur support is guaranteed for elements that a user can interact with: <input>, <button>, <a>, and more.

On the other hand, elements that exist for formatting something, such as <span>, <div>, <table> - are non focusable by default. The elem.focus() method doesn’t operate on them, and focus/blur events never trigger.

That situation can be changed with HTML-attribute tabindex.

When an element has tabindex, it becomes non focusable. The attribute value is the order number of the element when Tab is applied for switching between them. In other words: if there are two elements and the first hastabindex="1", the second- tabindex="2", using Tab while in the first one, moves the focus into the second.

The switch order is as follows: elements with tabindex from 1 and above go first and only then go the elements without. Elements that have matching tabindex are switched in the document source order.

Two special values exist:

  • tabindex="0" that places an element amid the ones without tabindex. In other words, when you switch elements, the ones with tabindex=0 go after those with tabindex ≥ 1.

    As a rule, it is used for making an element focusable, keeping the default switching order.

  • tabindex="-1" is used only for programmatic focusing on an element. The Tab key ignores elements like that, but the elem.focus() method works.

Let’s take a look at the example below:

<!-- You should click the first item pressing the Tab. Keep track of the order. Please consider that many subsequent Tabs are capable of moving the focus out of the iframe with the example.-->
<!DOCTYPE HTML> 
<html>
  <head>
    <style>
      li { 
       cursor: pointer; 
      }
      :focus {
       outline: 2px solid red; 
      }
    </style>
  </head>
  <body>
    <ul>
      <li tabindex="1">One</li>
      <li tabindex="0">Zero</li>
      <li tabindex="-1">Minus one</li>
      <li tabindex="2">Two</li>
    </ul>
  </body>
</html>

Also, you can add tabindex from JavaScript by applying the elem.tabIndex property. The effect will be the same.

Delegation: focusin/focusout

The focus and blur events don’t bubble.

For example, it is not possible to put onfocus on the <form> to highlight it, as follows:

<!DOCTYPE HTML> 
<html>
  <head>
    <style>
      .focused { 
      outline: 1px solid red; 
      } 
    </style>
  </head>
  <body>
    <!-- on focusing in the form - add the class -->
    <form onfocus="this.className='focused'">
      <input type="text" name="firstname" value="FirstName">
      <input type="text" name="lastname" value="LasName">
    </form>
  </body>
</html>

The reason that the code above doesn’t work is that when the user focuses on the <input>, the focus event triggers on that input only. As it doesn’t bubble up, the form.onfocus doesn’t trigger either.

In such a case, we can suggest two solutions.

Within the first solution, focus/blur don’t bubble up but propagate down on the capturing phase. Hence, this is a working example:

<!DOCTYPE HTML> 
<html>
  <head>
    <style>
      .focused {
        outline: 1px solid red;
      } 
    </style>
  </head>
  <body>
    <form id="form">
      <input type="text" name="firstname" value="FirstName">
      <input type="text" name="lastname" value="LastName">
    </form>
    <script>
      // put the handler on capturing phase, last argument true
      form.addEventListener("focus", () => form.classList.add('focused'), true);
      form.addEventListener("blur", () => form.classList.remove('focused'), true);
    </script>
  </body>
</html>

And, finally, there are focusin and focusout events, similar to focus/blur. The difference is that they can bubble. They should be assigned by applying elem.addEventListener , not on<event> .

The example of using the focusin and focusout events looks like this:

<!DOCTYPE HTML> 
<html>
  <head>
    <style>
      .focused {
        outline: 1px solid red;
      } 
    </style>
  </head>
  <body>
    <form id="form">
      <input type="text" name="firstname" value="FirstName">
      <input type="text" name="lastname" value="LastName">
    </form>
    <script>
      form.addEventListener("focusin", () => form.classList.add('focused'));
      form.addEventListener("focusout", () => form.classList.remove('focused'));
    </script>
  </body>
</html>

Summary

The focus and blur events are a crucial part of any programming activity.

The focus event triggers on focusing, while the blur event happens when the focus is lost.

They have several specific features that are described below:

  • They never bubble. But, instead, you can use focusin/focusout that can bubble.
  • By default, the focus is not supported by most elements. The good thing is that you can use tabindex for making anything focusable.

And, finally, the currently focused element may be available in document.activeElement.




Do you find this helpful?

Related articles