Which HTML elements can receive focus?

HtmlFocus

Html Problem Overview


I'm looking for a definitive list of HTML elements which are allowed to take focus, i.e. which elements will be put into focus when focus() is called on them?

I'm writing a jQuery extension which works on elements that can be brought into focus. I hope the answer to this question will allow me to be specific about the elements I target.

Html Solutions


Solution 1 - Html

There isn't a definite list, it's up to the browser. The only standard we have is DOM Level 2 HTML, according to which the only elements that have a focus() method are HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement and HTMLAnchorElement. This notably omits HTMLButtonElement and HTMLAreaElement.

Today's browsers define focus() on HTMLElement, but an element won't actually take focus unless it's one of:

  • HTMLAnchorElement/HTMLAreaElement with an href
  • HTMLInputElement/HTMLSelectElement/HTMLTextAreaElement/HTMLButtonElement but not with disabled (IE actually gives you an error if you try), and file uploads have unusual behaviour for security reasons
  • HTMLIFrameElement (though focusing it doesn't do anything useful). Other embedding elements also, maybe, I haven't tested them all.
  • Any element with a tabindex

There are likely to be other subtle exceptions and additions to this behaviour depending on browser.

Solution 2 - Html

Here I have a CSS-selector based on bobince's answer to select any focusable HTML element:

  a[href]:not([tabindex='-1']),
  area[href]:not([tabindex='-1']),
  input:not([disabled]):not([tabindex='-1']),
  select:not([disabled]):not([tabindex='-1']),
  textarea:not([disabled]):not([tabindex='-1']),
  button:not([disabled]):not([tabindex='-1']),
  iframe:not([tabindex='-1']),
  [tabindex]:not([tabindex='-1']),
  [contentEditable=true]:not([tabindex='-1'])
  {
      /* your CSS for focusable elements goes here */
  }

or a little more beautiful in SASS:

a[href],
area[href],
input:not([disabled]),
select:not([disabled]),
textarea:not([disabled]),
button:not([disabled]),
iframe,
[tabindex],
[contentEditable=true]
{
	&:not([tabindex='-1'])
	{
		/* your SCSS for focusable elements goes here */
	}
}

I've added it as an answer, because that was, what I was looking for, when Google redirected me to this Stackoverflow question.

EDIT: There is one more selector, which is focusable:

[contentEditable=true]

However, this is used very rarely.

Solution 3 - Html

$focusable:
  'a[href]',
  'area[href]',
  'button',
  'details',
  'input',
  'iframe',
  'select',
  'textarea',

  // these are actually case sensitive but i'm not listing out all the possible variants
  '[contentEditable=""]',
  '[contentEditable="true"]',
  '[contentEditable="TRUE"]',

  '[tabindex]:not([tabindex^="-"])',
  ':not([disabled])';

I'm creating a SCSS list of all focusable elements and I thought this might help someone due to this question's Google rank.

A few things to note:

  • I changed :not([tabindex="-1"]) to :not([tabindex^="-"]) because it's perfectly plausible to generate -2 somehow. Better safe than sorry right?
  • Adding :not([tabindex^="-"]) to all the other focusable selectors is completely pointless. When using [tabindex]:not([tabindex^="-"]) it already includes all elements that you'd be negating with :not!
  • I included :not([disabled]) because disabled elements can never be focusable. So again it's useless to add it to every single element.

Solution 4 - Html

The ally.js accessibility library provides an unofficial, test-based list here:

https://allyjs.io/data-tables/focusable.html

(NB: Their page doesn't say how often tests were performed.)

Solution 5 - Html

Maybe this one can help:

function focus(el){
	el.focus();
	return el==document.activeElement;
}

return value: true = success, false = failed

Reff: https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/activeElement https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus

Solution 6 - Html

There is a much more elegant way to handle this:

Extend the element prototype like the sample below. Then you can use it like:

element.isFocusable()

*Returns true if "element" is focusable and false if not.

/**
* Determining if an element can be focused on
* @return   {Boolean}
*/
HTMLElement.prototype.isFocusable = function () {
  var current = document.activeElement
  if (current === this) return true
  var protectEvent = (e) => e.stopImmediatePropagation()
  this.addEventListener("focus", protectEvent, true)
  this.addEventListener("blur", protectEvent, true)
  this.focus({preventScroll:true})
  var result = document.activeElement === this
  this.blur()
  if (current) current.focus({preventScroll:true})
  this.removeEventListener("focus", protectEvent, true)
  this.removeEventListener("blur", protectEvent, true)
  return result
}

// A SIMPLE TEST
console.log(document.querySelector('a').isFocusable())
console.log(document.querySelector('a[href]').isFocusable())

<a>Not focusable</a>
<a href="#">Focusable</a>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPaul TurnerView Question on Stackoverflow
Solution 1 - HtmlbobinceView Answer on Stackoverflow
Solution 2 - HtmlReeCubeView Answer on Stackoverflow
Solution 3 - HtmlwhaleyView Answer on Stackoverflow
Solution 4 - HtmllingView Answer on Stackoverflow
Solution 5 - HtmlYohannes KristiawanView Answer on Stackoverflow
Solution 6 - HtmlBondsmithView Answer on Stackoverflow