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
    39 Shirts – Leaving Mozilla

    In 2001 I had just graduated from a small town high school and headed off to a small town college. I found myself in the quaint computer lab where the substandard computers featured two browsers: Internet Explorer and Mozilla. It was this lab where I fell...

  • 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
    Creating Spacers with Flexbox

    I was one of the biggest fans of flexbox before it hit but, due to being shuffled around at Mozilla, I never had the chance to use it in any practice project; thus, flexbox still seems like a bit of a mystery to me.  This greatly...

  • By
    Create a Dynamic Table of Contents Using MooTools 1.2

    You've probably noticed that I shy away from writing really long articles. Here are a few reasons why: Most site visitors are coming from Google and just want a straight to the point, bail-me-out ASAP answer to a question. I've noticed that I have a hard time...

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!