Introducing onFocus and onBlur

By YUI TeamOctober 7, 2008

Back in April, PPK authored a blog entry titled Delegating the focus and blur events in which he proposed a solution to the problem that neither the focus or blur events bubble in any browser. His solution (registering capture-phase event listeners for focus and blur) is a blessing to any developer wishing to avoid the code bloat and performance bottleneck that can result from binding discrete focus and blur event handlers for focusable elements.

We liked PPK's solution and decided to answer his call and be, in his words, " of those frightfully clever JavaScript librar[ies to] use this technique...". So for version 2.6 we've rolled PPK's solution into two methods of the Event Utility: addFocusListener and addBlurListener (or onFocus and onBlur for short). These two new methods encapsulate the nitty gritty of supporting this technique in all our A-Grade browsers, while delivering the sugar you've come to expect from the addListener method of the Event Utility. The signatures of these new methods are as follows:

onFocus(el, fn, obj, override)
oBlur(el, fn, obj, override)

The arguments for both methods are as follows:

An id, an element reference, or a collection of ids and/or elements to assign the listener to.
The method the event invokes.
An arbitrary object that will be passed as a parameter to the handler.
override If true, the obj passed in becomes the execution scope of the listener. If an object, this object becomes the execution scope.

Using onFocus and onBlur

Here are several ways we've made use of the new onFocus and onBlur methods in YUI 2.6:

Improving Performance of Modal Dialogs

To support modality, a Dialog widget needs to direct focus back to itself when an element that is not one of its children receives focus. Previously this was accomplished by registering focus event listeners on every focusable element in the document when a modal Dialog was made visible, and removing those listeners when it has was hidden, a process that proved to be expensive and slow. Using PPK's technique we've been able to boost the time it takes to initially display a modal Dialog by over 50% in most browsers, and boost the time it takes to hide a modal Dialog by over 90%. To test, we used a page with 250 focusable elements. Here is how the numbers break out for each browser:

Time (in milliseconds) to initially display a modal Dialog widget on a page with 250 focusable elements in YUI 2.5.2 and YUI 2.6.0
Browser YUI 2.5.2 YUI 2.6.0 % Faster
FF 3 Mac OS 10.4 245 107 56
FF 3 Win XP 158 88 44
FF 2 Mac OS 10.4 368 161 56
FF 2 Win XP 320 131 59
Opera 9.5 Mac OS 10.4 103 93 10
Opera 9.5 Win XP 71 60 15
IE 7 200 70 65
IE 6 220 121 45
Safari 3.1 53 18 66
Time (in milliseconds) to hide a modal Dialog widget on a page with 250 focusable elements in YUI 2.5.2 and YUI 2.6.0
Browser YUI 2.5.2 YUI 2.6.0 % Faster
FF 3 Mac OS 10.4 65 1 98
FF 3 Win XP 57 1 98
FF 2 Mac OS 10.4 198 2 99
FF 2 Win XP 221 0 100
Opera 9.5 Mac OS 10.4 531 1 100
Opera 9.5 Win XP 380 0 100
IE 7 381 30 92
IE 6 371 40 89
Safari 3.1 48 1 98

Improving Menu Keyboard Accessibility

In keeping with the WAI-ARIA Best Practices for Menus, the Menu widget uses the new onFocus method to listen for focus at the document level, so that when a popup Menu is hidden focus can be restored to the element in the DOM that had focus before it was made visible.

Providing Focus Feedback in Carousel

The new Carousel widget skins its next and previous buttons by wrapping each <input type="button"> elements in a <span>. The <input> elements are then positioned off screen and a background image is applied to each <span>. While this technique allows the next and previous buttons to remain accessible to users of screen readers, with the actual next and previous buttons hidden off screen, sighted users don't receive any feedback from the UI when either button is focused. To fix this problem, Carousel uses the onFocus method to apply a class to the next and previous buttons that highlights focused buttons with an outline.

Of course, these are just a few places where we've used onFocus and onBlur — we think it will prove so useful in YUI and in YUI-based applications that we've added it to our Core, making it available to any application you build on top of YUI's Event Utility.