Get the Focused Element with JavaScript

By  on  

Ensuring that a website or web app is both accessible and usable, as well as functional, is paramount to a positive user experience for all users.  Users don't appreciate when we've done a good job, but they definitely know when we've done poorly.  One important part of app usability and accessibility is focus management, a task often overlooked by developers.

A prime example of poor focus management:  opening a modal upon clicking a triggering link, not focusing on the any element in the modal.  Even worse:  focusing on one of the modal's elements but not returning focus to its trigger element once it has been closed.  Ideally you would store a reference to the trigger, focus into the modal, and focus back on the trigger element when the modal is closed.

What about the times when you aren't aware of which element is focused though?  The document tells us which element is focused via the document.activeElement property!

The JavaScript

Retrieving the currently selected element is as easy as using document.activeElement:

var focusedElement = document.activeElement;

/* per my example:
	var triggerElement = document.activeElement;
	myModal = new MyModal({
		onOpen: function() {
			this.container.focus();
		},
		onClose: function() {
			triggerElement.focus();
		}
	});
*/

This property isn't simply reserved for traditionally focusable elements, like form fields and links, but also any element with a positive tabIndex set.

What I love about document.activeElement is that you don't need any type of event listener or delegated listener to keep track of what element is focused -- you can simply reference that one property at any time.  Of course you should do loads of testing before relying on a feature like this -- it seems ripe for cross-browser issues or race conditions.  All in all, however, I've been pleased with my use of it and its reliability!

Recent Features

  • By
    5 Awesome New Mozilla Technologies You’ve Never Heard Of

    My trip to Mozilla Summit 2013 was incredible.  I've spent so much time focusing on my project that I had lost sight of all of the great work Mozillians were putting out.  MozSummit provided the perfect reminder of how brilliant my colleagues are and how much...

  • By
    An Interview with Eric Meyer

    Your early CSS books were instrumental in pushing my love for front end technologies. What was it about CSS that you fell in love with and drove you to write about it? At first blush, it was the simplicity of it as compared to the table-and-spacer...

Incredible Demos

  • By
    Retrieve Your Gmail Emails Using PHP and IMAP

    Grabbing emails from your Gmail account using PHP is probably easier than you think. Armed with PHP and its IMAP extension, you can retrieve emails from your Gmail account in no time! Just for fun, I'll be using the MooTools Fx.Accordion plugin...

  • By
    CSS Gradients

    With CSS border-radius, I showed you how CSS can bridge the gap between design and development by adding rounded corners to elements.  CSS gradients are another step in that direction.  Now that CSS gradients are supported in Internet Explorer 8+, Firefox, Safari, and Chrome...

Discussion

  1. Darius Kruythoff

    If memory serves me, this breaks in IE9 within iframes.
    try/catch can help here.

  2. Gwyn

    Thanks, this seems to be a good technique. I hadn’t thought of using focus outside of links and form fields. Would you recommend this for a tabbed interface (switching focus between tabpanels?

  3. olivvv

    to detail our twitter exchange, wrapping document.activeElement in a setTimeout is necessary when you want to catch it onblur().

  4. MDN claims that on a Mac elements that are not a text input tends to *not* get focus assigned to them (https://developer.mozilla.org/en-US/docs/Web/API/document.activeElement). I haven’t experimented enough to provide any useful tips but it’s definitely something to look out for.

    • I did see that, though I experienced no issues on non-input elements, so I didn’t mention it.

  5. Karl Swedberg

    Hey David,

    Thanks for this post! I’m guessing the MDN note about elements other than text inputs not getting focus is referring to OS X Safari in particular. Also, the “Full Keyboard Access” setting in System Preferences > Keyboard > Shortcuts seems to have an effect on it. I put together a little demo: http://jsbin.com/dofiv/1/edit?html,js,console,output

    * With the default “Full Keyboard Access” setting — “Text boxes and lists only” — the radio inputs and button don’t get focus when clicked and can’t be tabbed into.
    * When “Full Keyboard Access” is set to “All controls,” only the radio with a tabindex attribute can be tabbed into, and that one doesn’t get focus when clicked.
    * I can’t tab into the a element regardless of the keyboard access setting, but it gets focus either way when clicked.
    * Interestingly, I can tab into the div element with tabindex and it gets focus click regardless of the keyboard access setting.

    For what it’s worth, here is what Sizzle does to determine the “active” element: https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L1299
    And this comment explains how it handles the IE8-9 iframe error: https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L603-L606

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!