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

Incredible Demos

  • By
    Vertically Centering with Flexbox

    Vertically centering sibling child contents is a task we've long needed on the web but has always seemed way more difficult than it should be.  We initially used tables to accomplish the task, then moved on to CSS and JavaScript tricks because table layout was horribly...

  • By
    Smooth Scrolling with MooTools Fx.SmoothScroll

    I get quite a few support requests for my previous MooTools SmoothScroll article and the issue usually boils down to the fact that SmoothScroll has become Fx.SmoothScroll. Here's a simple usage of Fx.SmoothScroll. The HTML The only HTML requirement for Fx.SmoothScroll is that all named...

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!