1613

I would like to find out, in JavaScript, which element currently has focus. I've been looking through the DOM and haven't found what I need, yet. Is there a way to do this, and how?

The reason I was looking for this:

I'm trying to make keys like the arrows and enter navigate through a table of input elements. Tab works now, but enter, and arrows do not by default it seems. I've got the key handling part set up but now I need to figure out how to move the focus over in the event handling functions.

Luca Kiebel
  • 9,790
  • 7
  • 29
  • 44
Tony Peterson
  • 20,522
  • 15
  • 48
  • 66
  • 4
    Here is a bookmarklet that console.log the element with focus: https://github.com/lingtalfi/where-is-focus-bookmarklet – ling Sep 26 '16 at 18:51
  • 1
    You can use `find-focused-element` package: https://www.npmjs.com/package/find-focused-element – Maxim Zhukov Apr 22 '20 at 15:54
  • 1
    For me the bookmarklet doesn't work that ling mentioned. – GarfieldKlon Aug 27 '20 at 07:43
  • 6
    See a good example of `document.activeElement` being used here: https://stackoverflow.com/a/64176168/1599699 – Andrew Oct 02 '20 at 19:08
  • For your specific use case you can make a graph that you can query to determine what should get focus based on the keyboard input event. `nextFocus(element, keyboardEvent) // => returns the element to receive focus` – bas080 Aug 08 '23 at 16:52

21 Answers21

1897

Use document.activeElement, it is supported in all major browsers.

Previously, if you were trying to find out what form field has focus, you could not. To emulate detection within older browsers, add a "focus" event handler to all fields and record the last-focused field in a variable. Add a "blur" handler to clear the variable upon a blur event for the last-focused field.

If you need to remove the activeElement you can use blur; document.activeElement.blur(). It will change the activeElement to body.

Related links:

Jonathan
  • 8,453
  • 9
  • 51
  • 74
JW.
  • 50,691
  • 36
  • 115
  • 143
  • 2
    If no element has been focused, what does document.activeElement return? Can we rely on it to be consistent between those browsers that support it? – Stewart Jul 02 '10 at 12:32
  • 69
    Not sure about IE, but FF and Safari both return the BODY element. – JW. Jul 02 '10 at 15:19
  • 1
    do we have access to know which element was previously focused? – Barry Sep 20 '11 at 22:01
  • 1
    No, you'd have to keep track of that yourself. – JW. Sep 21 '11 at 17:30
  • 16
    `activeElement` actually doesn't return the focused element. Any element can have focus. If a document has 4 'scrolldivs', 0 or 1 of those divs is scrollable by arrow keys. If you click one, that div is focused. If you click outside all, the body is focused. How do you find out which scrolldiv is focused? http://jsfiddle.net/rudiedirkx/bC5ke/show/ (check console) – Rudie Oct 22 '12 at 22:40
  • 25
    @Rudie, @Stewart: I've built on your fiddle to create a more elaborate playground: http://jsfiddle.net/mklement/72rTF/. You'll find that the only major browser (as of late 2012) that can actually focus such a `div` is Firefox 17, and only by _tabbing_ to it. The types of elements that ALL major browsers return via `document.activeElement` are restricted to _input_-related elements. If no such element has the focus, all major browsers return the `body` element - except IE 9, which returns the `html` element. – mklement0 Dec 22 '12 at 05:20
  • 1
    @JW: IE (as of v9) returns the `html` element. Current versions (as of late 2012) of Safari, Chrome, Firefox, Opera all return the `body` element. – mklement0 Dec 22 '12 at 05:25
  • 1
    In XHTML documents, `'activeElement' in document` is `false` in Chrome (26). `document.querySelector(':focus')` works fine though, if you want to know if any input element is focused. – Rob W Mar 30 '13 at 17:28
  • 16
    Not sure if it helps, but you can make an element such as a div receive keyboard focus by including the attribute tabindex="0" – Marco Luglio Apr 12 '13 at 16:49
  • 6
    Any access to `document.activeElement` should be wrapped in a `try catch` as under some circumstances it can throw an exception (not just IE9 AFAIK). See http://bugs.jquery.com/ticket/13393 and http://bugs.jqueryui.com/ticket/8443 – robocat Jul 02 '13 at 02:11
  • 2
    I updated @mklement / Rudie's jsfiddle. As facildelembrar stated, you can access it with tabindex. See http://jsfiddle.net/72rTF/34/ – inanutshellus Jun 11 '14 at 16:11
  • 1
    I am not sure why people say it is not supported .. as it seems to have been supported eons ago .. https://www.w3schools.com/jsref/prop_document_activeelement.asp – Ken May 01 '20 at 23:27
  • 1
    Is this true even when using framesets? Is there an implication that only ONE element between all the frames can be the activeElement ? – Marcel Wilson Oct 28 '20 at 18:05
  • This doesn't work for `` or at least ` – ygoe Feb 13 '21 at 14:00
  • use ``document.activeElement.id`` - filters out unidentified elements – cloudxix Jul 17 '22 at 22:09
157

As said by JW, you can't find the current focused element, at least in a browser-independent way. But if your app is IE only (some are...), you can find it the following way:

document.activeElement

It looks like IE did not have everything wrong after all, this is part of HTML5 draft and seems to be supported by the latest version of Chrome, Safari and Firefox at least.

Iurii Tkachenko
  • 3,106
  • 29
  • 34
Wookai
  • 20,883
  • 16
  • 73
  • 86
  • 5
    FF3 too. This is actually part of the HTML5 spec around "focus management". – Crescent Fresh Jan 31 '09 at 00:37
  • 2
    It works in the current version of Chrome and Opera (9.62). Does not work in Safari 3.2.3 on OS X, but it works in Safari 4 that was released yesterday :) – gregers Jun 09 '09 at 15:02
  • still the same for chrome 19 :S – Sebas Jun 20 '12 at 23:12
  • 1
    It only works in chrome (20) / safari (5.1.3) when you use the keyboard to tab onto the element. If you click on it then neither the jquery :focus selector nor the document.activeElement succeeds in returning what you clicked on (returning undefined and document body element respectively). PS I can't believe this thread is 2 years old and there are still regression problems on webkit, along with the one where skip links don't work, but so much work is being done with adding experimental css3. Think I may go back to recommending firefox to my family and friends. – Dawn Jul 05 '12 at 11:03
  • ^^ document.activeElement is fine when you click to focus on a text area or other input. If it is a link it won't focus when clicked on (in page or obviously otherwise). – marksyzm Sep 10 '13 at 13:39
  • 1
    It returns 'body' for most of the elements. Pretty much useless. – Cornelius Mar 21 '20 at 12:46
  • is it still impossible to find the element with focus? why when i deliberately focus an element (i.e. `ele.focus()`) and then check `document.activeElement`, it always returns the document's body? – oldboy Nov 13 '20 at 10:13
96

If you can use jQuery, it now supports :focus, just make sure you are using version 1.6+.

This statement will get you the currently focused element.

$(":focus")

From: How to select an element that has focus on it with jQuery

Community
  • 1
  • 1
William Denniss
  • 16,089
  • 7
  • 81
  • 124
  • 6
    This is good, but how does jQuery do it? document.activeElement? I found this: `return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);` – Harry Pehkonen Oct 13 '17 at 03:16
  • 1
    @HarryPehkonen Looks like common `document.querySelector( ':focus' )` works just fine and is used by jQuery – V.Volkov Aug 20 '22 at 20:14
52

document.activeElement is now part of the HTML5 working draft specification, but it might not yet be supported in some non-major/mobile/older browsers. You can fall back to querySelector (if that is supported). It's also worth mentioning that document.activeElement will return document.body if no element is focused — even if the browser window doesn't have focus.

The following code will work around this issue and fall back to querySelector giving a little better support.

var focused = document.activeElement;
if (!focused || focused == document.body)
    focused = null;
else if (document.querySelector)
    focused = document.querySelector(":focus");

An addition thing to note is the performance difference between these two methods. Querying the document with selectors will always be much slower than accessing the activeElement property. See this jsperf.com test.

Andy E
  • 338,112
  • 86
  • 474
  • 445
42

By itself, document.activeElement can still return an element if the document isn't focused (and thus nothing in the document is focused!)

You may want that behavior, or it may not matter (e.g. within a keydown event), but if you need to know something is actually focused, you can additionally check document.hasFocus().

The following will give you the focused element if there is one, or else null.

var focused_element = null;
if (
    document.hasFocus() &&
    document.activeElement !== document.body &&
    document.activeElement !== document.documentElement
) {
    focused_element = document.activeElement;
}

To check whether a specific element has focus, it's simpler:

var input_focused = document.activeElement === input && document.hasFocus();

To check whether anything is focused, it's more complex again:

var anything_is_focused = (
    document.hasFocus() &&
    document.activeElement !== null &&
    document.activeElement !== document.body &&
    document.activeElement !== document.documentElement
);

Robustness Note: In the code where it the checks against document.body and document.documentElement, this is because some browsers return one of these or null when nothing is focused.

It doesn't account for if the <body> (or maybe <html>) had a tabIndex attribute and thus could actually be focused. If you're writing a library or something and want it to be robust, you should probably handle that somehow.


Here's a (heavy airquotes) "one-liner" version of getting the focused element, which is conceptually more complicated because you have to know about short-circuiting, and y'know, it obviously doesn't fit on one line, assuming you want it to be readable.
I'm not gonna recommend this one. But if you're a 1337 hax0r, idk... it's there.
You could also remove the || null part if you don't mind getting false in some cases. (You could still get null if document.activeElement is null):

var focused_element = (
    document.hasFocus() &&
    document.activeElement !== document.body &&
    document.activeElement !== document.documentElement &&
    document.activeElement
) || null;

For checking if a specific element is focused, alternatively you could use events, but this way requires setup (and potentially teardown), and importantly, assumes an initial state:

var input_focused = false;
input.addEventListener("focus", function() {
    input_focused = true;
});
input.addEventListener("blur", function() {
    input_focused = false;
});

You could fix the initial state assumption by using the non-evented way, but then you might as well just use that instead.

1j01
  • 3,714
  • 2
  • 29
  • 30
22

document.activeElement may default to the <body> element if no focusable elements are in focus. Additionally, if an element is focused and the browser window is blurred, activeElement will continue to hold the focused element.

If either of these two behaviors are not desirable, consider a CSS-based approach: document.querySelector( ':focus' ).

Nate Whittaker
  • 1,866
  • 15
  • 14
  • Cool, yes in my case your approach made absolutly sense. I can set my focusable elements with 'tabindex="-1" ', if none of them has focus (let's say, some text or picture, that I don't care about) the document.querySelector( ':focus') returns null. – Manfred May 10 '15 at 13:49
  • See my answer to avoid using `querySelector`: http://stackoverflow.com/a/40873560/2624876 – 1j01 Nov 29 '16 at 19:12
15

I have found the following snippet to be useful when trying to determine which element currently has focus. Copy the following into the console of your browser, and every second it will print out the details of the current element that has focus.

setInterval(function() { console.log(document.querySelector(":focus")); }, 1000);

Feel free to modify the console.log to log out something different to help you pinpoint the exact element if printing out the whole element does not help you pinpoint the element.

vegemite4me
  • 6,621
  • 5
  • 53
  • 79
12

A little helper that I've used for these purposes in Mootools:

FocusTracker = {
    startFocusTracking: function() {
       this.store('hasFocus', false);
       this.addEvent('focus', function() { this.store('hasFocus', true); });
       this.addEvent('blur', function() { this.store('hasFocus', false); });
    },

    hasFocus: function() {
       return this.retrieve('hasFocus');
    }
}

Element.implement(FocusTracker);

This way you can check if element has focus with el.hasFocus() provided that startFocusTracking() has been called on the given element.

Bonifacio2
  • 3,405
  • 6
  • 34
  • 54
Joel S
  • 498
  • 6
  • 17
12

I liked the approach used by Joel S, but I also love the simplicity of document.activeElement. I used jQuery and combined the two. Older browsers that don't support document.activeElement will use jQuery.data() to store the value of 'hasFocus'. Newer browsers will use document.activeElement. I assume that document.activeElement will have better performance.

(function($) {
var settings;
$.fn.focusTracker = function(options) {
    settings = $.extend({}, $.focusTracker.defaults, options);

    if (!document.activeElement) {
        this.each(function() {
            var $this = $(this).data('hasFocus', false);

            $this.focus(function(event) {
                $this.data('hasFocus', true);
            });
            $this.blur(function(event) {
                $this.data('hasFocus', false);
            });
        });
    }
    return this;
};

$.fn.hasFocus = function() {
    if (this.length === 0) { return false; }
    if (document.activeElement) {
        return this.get(0) === document.activeElement;
    }
    return this.data('hasFocus');
};

$.focusTracker = {
    defaults: {
        context: 'body'
    },
    focusedElement: function(context) {
        var focused;
        if (!context) { context = settings.context; }
        if (document.activeElement) {
            if ($(document.activeElement).closest(context).length > 0) {
                focused = document.activeElement;
            }
        } else {
            $(':visible:enabled', context).each(function() {
                if ($(this).data('hasFocus')) {
                    focused = this;
                    return false;
                }
            });
        }
        return $(focused);
    }
};
})(jQuery);
Jason
  • 803
  • 9
  • 15
  • 3
    Could this be replaced by @William Denniss's `$("*:focus")` ? – Pylinux Jul 30 '15 at 10:30
  • I suppose it could. I wrote this a long time ago and never had a reason to revisit a better solution now that it is 5 years later. Try it out! I might just do the same. I less plugin on our site! :) – Jason Aug 21 '15 at 19:33
9

If you want to get a object that is instance of Element, you must use document.activeElement, but if you want to get a object that is instance of Text, you must to use document.getSelection().focusNode.

I hope helps.

rplaurindo
  • 1,277
  • 14
  • 23
  • Better in what way? – 1j01 Nov 29 '16 at 19:10
  • Open your browser’s inspector, click on any place of the page, past this ```document.getSelection().focusNode.parentElement``` and tap Enter. After that, past ```document.activeElement``` and do it samething. ;) – rplaurindo Nov 29 '16 at 19:22
  • With this comment box focused, `document.activeElement` gives the ` – 1j01 Dec 01 '16 at 02:37
  • Sorry, my apologies. I didn’t explain it well. If you want to get a object that is instance of ```Element```, you must to use ```document.activeElement```, but if you want to get a object that is instance of ```Text```, you must to use ```document.getSelection().focusNode```. Please, test it again. I hope I helped. – rplaurindo Dec 01 '16 at 03:53
  • 2
    The question is asking for which element currently has focus. And the `focusNode` isn't guaranteed to be a text node either. – 1j01 Dec 02 '16 at 06:45
  • Yes, but the ```activeElement``` never will return a ```Text``` object. ```document.getSelection().focusNode``` guarantees a instance of ```Node```, that cans to be a ```Text``` or a ```Element``` after click in an element, for example. It's not a question of being better, but more appropriate. – rplaurindo Dec 02 '16 at 12:29
  • But the question asked for an element, i.e. an `Element`. It's fine (in my opinion) to answer a question by mentioning a similar situation under which you'd want a different solution, but "if you want to get a text node" isn't very descriptive. What did you use this for, for instance? – 1j01 Dec 03 '16 at 04:08
  • Yes, the question was about a element. I took advantage of it and added the information to a different case. It is important note that some people make confusion, and believe that a text node is an element, when in fact, element is what encapsulates a text. Being ```Element``` and ```Text``` instances of ```Node```, but a ```Text``` doesn’t is an ```Element```. So... I used for get an object that was selected on HTML, then show a tooltip above it. – rplaurindo Dec 03 '16 at 21:31
  • Okay, yeah, that's definitely a different case. Selection isn't focus. – 1j01 Dec 03 '16 at 21:39
  • It really is not. But could be a click event case over a text rather than a selection. So much so that the ```FOCUSNode``` attribute exists for the object returned by the ```getSelection``` method. – rplaurindo Dec 03 '16 at 21:53
  • it's very useful when you need to set different action for input things. though it's not about getting current element when focusout triggers, guess no better way. there's no use case to get the element when focusout. if you need, that is better use mouseout. – Chase Choi Jul 23 '18 at 09:35
9

JQuery does support the :focus pseudo-class as of current. If you are looking for it in the JQuery documentation, check under "Selectors" where it points you to the W3C CSS docs. I've tested with Chrome, FF, and IE 7+. Note that for it to work in IE, <!DOCTYPE... must exist on the html page. Here is an example assuming you've assigned an id to the element that has focus:

$(":focus").each(function() {
  alert($(this).attr("id") + " has focus!");
});
Andrew Wynham
  • 2,310
  • 21
  • 25
  • 1
    You should (always?) use `this.id` instead of `$(this).attr('id')`, or at least (when you allready have your jQuery object) `$(this)[0].id`. Native Javascript at this level is WAY faster and more efficient. Might not be noticable in this case, but systemwide you will notice a difference. – Martijn Dec 15 '15 at 13:51
8

There are potential problems with using document.activeElement. Consider:

<div contentEditable="true">
  <div>Some text</div>
  <div>Some text</div>
  <div>Some text</div>
</div>

If the user focuses on an inner-div, then document.activeElement still references the outer div. You cannot use document.activeElement to determine which of the inner div's has focus.

The following function gets around this, and returns the focused node:

function active_node(){
  return window.getSelection().anchorNode;
}

If you would rather get the focused element, use:

function active_element(){
  var anchor = window.getSelection().anchorNode;
  if(anchor.nodeType == 3){
        return anchor.parentNode;
  }else if(anchor.nodeType == 1){
        return anchor;
  }
}
Nathan K
  • 316
  • 3
  • 6
  • 3
    That's not really a problem with `document.activeElement`: the inner `
    ` elements actually can't receive focus, as you can see visually by setting the `:focus` pseudo-class to something visible (example: http://jsfiddle.net/4gasa1t2/1/). What you're talking about is which of the inner `
    `s contains the selection or caret, which is a separate issue.
    – Tim Down Jul 19 '15 at 09:59
7

If you're using jQuery, you can use this to find out if an element is active:

$("input#id").is(":active");
Arne
  • 6,140
  • 2
  • 21
  • 20
6

Reading other answers, and trying myself, it seems document.activeElement will give you the element you need in most browsers.

If you have a browser that doesn't support document.activeElement if you have jQuery around, you should be able populate it on all focus events with something very simple like this (untested as I don't have a browser meeting those criteria to hand):

if (typeof document.activeElement === 'undefined') { // Check browser doesn't do it anyway
  $('*').live('focus', function () { // Attach to all focus events using .live()
    document.activeElement = this; // Set activeElement to the element that has been focussed
  });
}
rjmunro
  • 27,203
  • 20
  • 110
  • 132
5

Just putting this here to give the solution I eventually came up with.

I created a property called document.activeInputArea, and used jQuery's HotKeys addon to trap keyboard events for arrow keys, tab and enter, and I created an event handler for clicking into input elements.

Then I adjusted the activeInputArea every time focus changed, so I could use that property to find out where I was.

It's easy to screw this up though, because if you have a bug in the system and focus isn't where you think it is, then its very hard to restore the correct focus.

Tony Peterson
  • 20,522
  • 15
  • 48
  • 66
5

With dojo, you can use dijit.getFocus()

Daniel Hartmann
  • 115
  • 1
  • 4
4

use document.activeElement.id

appending .id filters out returning the entire DOM and allows you to work only with identified elements

cloudxix
  • 416
  • 1
  • 6
  • 11
3

simple use document.activeElement to find the current active element

Rahul Daksh
  • 212
  • 1
  • 7
2

I think that Christian's answer is closest to the correct answer; with the addition that the focusout event has a property named relatedTarget that allows one to figure out what received the focus.

document.addEventListener("focusout",ev => {
  const focusedElement = ev.relatedTarget;

  // ...
});

The other answers that use querySelector(':focus') and activeElement have annoying caveats.

https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/relatedTarget

bas080
  • 341
  • 3
  • 9
0

If you want to test the focused element on the dev tools, I suggest using.

$(":focus")

As document.activeElement will change to body when you click on anything in the dev tool.

Add focus attribute to the input

$(":focus" vs document.activeElement)

Mina
  • 14,386
  • 3
  • 13
  • 26
0

To get the previous active element add this.

Example: you click on a button and need the previous active element. Since the button gets the focus once click on it.

document.addEventListener("focusout",ev => {
  document.previousActiveElement = ev.target;
});
Christian
  • 57
  • 2
  • Tony wants the currently active element and your code will return last active element. – Ahmed Syed Jul 17 '22 at 15:12
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 17 '22 at 15:13