Build Status
Greenkeeper badge

Based on the proposed CSS
this prototype adds a focus-visible class to the focused element,
in situations in which the :focus-visible pseudo-selector should match.




npm install --save focus-visible

We recommend only using versions of the polyfill that have been published to npm, rather than
cloning the repo and using the source directly. This helps ensure the version you're using is stable
and thoroughly tested.

If you do want to build from source, make sure you clone the latest tag!


1. Add the script to your page

    <script src="/node_modules/focus-visible/dist/focus-visible.min.js"></script>

2. Update your CSS

We suggest that users
selectively disable the default focus style
by selecting for the case when the polyfill is loaded
and .focus-visible is not applied to the element:

  This will hide the focus indicator if the element receives focus via the mouse,
  but it will still show up on keyboard focus.
.js-focus-visible :focus:not(.focus-visible) {
  outline: none;

If there are elements which should always have a focus ring shown,
authors may explicitly add the focus-visible class.
If explicitly added, it will not be removed on blur.

Alternatively, if you're using a framework which overwrites your classes (#179),
you can rely on the data-focus-visible-added attribute.

.js-focus-visible :focus:not([data-focus-visible-added]) {
  outline: none;

How it works

The script uses two heuristics to determine whether the keyboard is being used:

  • a focus event immediately following a keydown event where the key pressed was either Tab,
    Shift + Tab, or an arrow key.
  • focus moves into an element which requires keyboard interaction,
    such as a text field
  • TODO: ideally, we also trigger keyboard modality
    following a keyboard event which activates an element or causes a mutation;
    this still needs to be implemented.


If you want to use :focus-visible with an older browser you'll need to include an additional polyfill for Element.prototype.classList.

In accordance with the W3C's new polyfill
, the
:focus-visible polyfill does not bundle other polyfills.

You can use a service like to download only the polyfills needed by the current browser. Just add the following line to the start of your page:

<script src=""></script>

Backwards compatibility

Until all browsers ship :focus-visible developers will need to use it defensively to avoid accidentally
removing focus styles in legacy browsers. This is easy to do with the polyfill.

  This will hide the focus indicator if the element receives focus via the mouse,
  but it will still show up on keyboard focus.
.js-focus-visible :focus:not(.focus-visible) {
  outline: none;

  Optionally: Define a strong focus indicator for keyboard focus.
  If you choose to skip this step then the browser's default focus
  indicator will be displayed instead.
.js-focus-visible .focus-visible {

As explained by the Paciello Group, developers who don't use the polyfill can still defensively rely on :focus-visible using the
following snippet:

  Provide basic, default focus styles.
button:focus {

  Remove default focus styles for mouse users ONLY if
  :focus-visible is supported on this platform.
button:focus:not(:focus-visible) {

  Optionally: If :focus-visible is supported on this
  platform, provide enhanced focus styles for keyboard
button:focus-visible {

In the future, when all browsers support :focus-visible, the
snippets above will be unnecessary. But until that time it's important
to be mindful when you use :focus-visible and to ensure you always
have a fallback strategy.

Big Thanks

Cross-browser Testing Platform and Open Source <3 Provided by Sauce Labs