Focus/Blur: methods and events

  1. The focus method
  2. Tabindex
  3. The blur event and method
  4. Non-bubbling
  5. Delegation with focus
    1. onblur
  6. Removing the dotted border on focused elements
  7. Summary

The focus event triggers when a visitor focuses on an element.

Not all elements are focusable by default. For example, INPUT and all types or form fields support this event, A supports it. As a counterexample, DIV doesn’t support focus.

The list of elements types which support focusing is slightly different between browsers. For IE, there is one at MSDN.

Here is an example of focus usage. The INPUT below changes it’s value on first click.

<input type="text" value="E-mail" class="untouched" value="E-mail"/>

<style> .untouched { color: gray } </style>

<script>
var input = document.getElementsByTagName('input')[0]

*!*input.onfocus*/!* = function() {
  if (this.className == '') return 
  this.className = ''
  this.value = ''
}
</script>

Note, that only the first focus removes the value. The starting value is a tip which is not needed anymore.

`getAttribute` to check for a change

A smarter one-line example checks if the value was modified using getAttribute:

<input name="email" type="text" value="E-mail">

<script>
var input = document.getElementsByTagName('input')[0]

input.onfocus = function() {
  if ( this.value == this.getAttribute('value') ) {
    this.value=''
  }
}
</script>

The code is fails in cases when user re-enters placeholder value.
But in most cases, the placeholder is never re-entered, so it works.

The focus method

A focusable element can receive a focus programmatically.
For example, let’s show a form and focus on it’s first input:

<form style="display:none" name="form">
  <input style="text" name="data" value="Data">
</form>

<input type="button" value="show form" onclick="showForm()">

<script>
function showForm() {
  var form = document.forms['form']
  form.style.display = 'block'
*!*
  form.elements[0].focus()
*/!*
}
</script>

Click on the button in the example above. The input will appear and receive focus.

Tabindex

Althgough not all elements are focusable but default, there is a tabindex attribute to fix that.

When you assign tabindex=<number> to an element:

  • It becomes focusable.
  • A user can use the tab key to move from the element with lesser positive tabindex to the next one. The exception is a special value tabindex="0" means that the element will always be last.
  • The tabindex=-1 means that an element becomes focusable, but the tab key will always skip it. Only the focus() method will work.

In the example below, there is a list with items. Click on any one of them and press the tab to make sure you understand the behavior.

<ul>
<li tabindex="1" onfocus="showFocus(this)">One</li>
<li tabindex="0" onfocus="showFocus(this)">Zero</li>
<li tabindex="2" onfocus="showFocus(this)">Two</li>
<li tabindex="-1" onfocus="showFocus(this)">Minus one</li>
</ul>

<span id="focus"></span>

<script>
function showFocus(elem) {
  document.getElementById('focus').innerHTML = "focus "+elem.tabIndex
}
</script>

Some browsers outline the focused element, some do not. This behavior depends on browser default styling, and can be changed by :focus CSS selector.

But all browsers support the tab navigation, even if the outline is absent. Try it. The order should be: 1 - 2 - 0.

A smart user knows what a “tab” key is and will try to use it. Your good attitude towards such users shall be rewarded Smile

The blur event and method

The blur is a counterpart of focus. The event gets triggered when an element loses focus. The elem.blur() makes an element to lose focus if it has it.

The bubbling analogs for blur are DOMFocusOut (Opera, Safari/Chrome) and focusout (IE).

In the example below, the input size is validated on blur. Type in something and click away from an element (or press tab) to activate blur.

<label>Enter your age: <input type="text" name="age"></label>
<div id="error"></div>

<script>
var input = document.getElementsByName('age')[0]
var errorHolder = document.getElementById('error')

*!*input.onfocus*/!* = function() {
  this.style.backgroundColor = ''
  errorHolder.innerHTML = ''
}

*!*input.onblur*/!* = function() {
  var age = +this.value 
  if (isNaN(age)) {
    this.style.backgroundColor = 'red'
    errorHolder.innerHTML = 'Enter a number please.'
  }
}
</script>

If visitor types in something non-numeric, or just nothing - a warning appears. Focusing on an input clears the warning, because it is not needed any more.

Non-bubbling

The focus event doesn’t bubble. It just happened in the history that it doesn’t, without a good reason.

Why I could want a bubbling focus? For instance, to make a form which outlines itself when focused:

<form onfocus="this.className='focused'">
  <input type="text" name="name" value="Your name">
  <input type="text" name="surname" value="Your surname">
</form>

<style>
form { text-align: center }
.focused { border: 3px groove red; }
</style>

The example above doesn’t work. An INPUT receives focus, but it doesn’t bubble up, so the FORM can’t catch it.

Do we really have to assign the handler to each input, or there is a way to delegate the event handling to the form?

Delegation with focus

To support event delegation with focus, there are currently 3 ways:

  1. The DOMFocusIn event is same as focus, but bubbles. It is supported only by Safari/Chrome and Opera (only can be assigned with addEventListener). The DOMFocusIn is deprecated in favor of focusin
  2. In newer standards, focusin replaces the junked DOMFocusIn event. IE supports it very well.
  3. In Firefox the only way is to catch focus on capturing phase.

So the code could be like that:

<form name="form">
  <input type="text" name="name" value="Your name">
  <input type="text" name="surname" value="Your surname">
</form>
<style>
form { text-align: center }
.focused { border: 3px groove red; }
</style>

<script>
function outline() { this.className='focused' }

var form = document.forms['form']

*!*
if (navigator.userAgent.indexOf('Firefox')>=0) { // Firefox
  form.addEventListener('focus', outline, true) 
} else if (form.addEventListener) {  // Opera, Safari/Chrome
  form.addEventListener('DOMFocusIn', outline, false)
} else {  // IE
  form.onfocusin = outline
}
*/!*
</script>

Try it, click on an input above. Works in all browsers.

Because we catch focus on the capturing phase for one browser and on the bubbling phase for others, our code must handle both cases. In most cases, like the form above, phase doesn’t matter.

As a consequence, usually only 2 ways are used: focusin for IE and focus on capture for all other browsers, without the DOMFocusIn branch.

So, the binding code shortens:

var form = document.forms['form']

if (form.addEventListener) { // W3C
  form.addEventListener('focus', outline, true) }
} else {  // IE
  form.onfocusin = outline
}

onblur

The onblur event behaves similarly. The corresponding bubbling events are: onDOMFocusOut and focusout

Removing the dotted border on focused elements

When a user focuses on a link, input or textfield, some browsers outline it.

Try clicking on these in Firefox, Safari/Chrome, IE. They are different in what they outline and how.

Sometimes you want to handle focusing on your own, and don’t need browser indication. Fortunately, we can disable it by pure CSS.

a:focus, input:focus { /* it should work, and it usually works */
  outline: none;
}

a:active, input:active {  /* for IE */
  outline: none; 
}

/* for buttons in Firefox */
button::-moz-focus-inner,
input[type="reset"]::-moz-focus-inner,
input[type="button"]::-moz-focus-inner,
input[type="submit"]::-moz-focus-inner,
input[type="file"] > input[type="button"]::-moz-focus-inner {
  border: none;
}

Summary

There are 3 ways to focus on an element:

  1. Mouse click
  2. Keyboard tab
  3. elem.focus() call

By default, many elements are not focusable. For example, if you click on a DIV, there will be no focus.

But they can made focusable by adding the tabIndex attribute. This attribute also allows to control keyboard tabs behavior.

The focus and blur events do not bubble.

In cases where bubbling could help, the solution is to use focusin/focusout in IE and focus/blur on capturing phase for other browsers.

Tutorial

Donate

Donate to this project