DEV Community

Cover image for Making focus-visible happen where do you live
d4g0
d4g0

Posted on

Making focus-visible happen where do you live

In case you don't know the focus-visible css selector allows us to target DOM elements that have been focused by a keyboard interaction, instead the traditional focus that targets every focused element.

Why do we need that distinction in the first place ?

It all starts with accessibility (a11y) in mind. If a user is browsing with a mouse or a phone, they know exactly what they are clicking. They don't need any clue about it, it might even become a distraction.

But it is a very different story for the keyboard user. Think for a moment, a father carrying their baby, people with injuries in a hand, people with a temporary or chronic health illness that disable them to use a mouse... there are a lot of them out there and you should be including them in your target audience. As Steve Krug says, it's the very right thing to do! no excuses.

If you haven't tried, go out there with your TAB key and browse around. You will need a visual feedback that shows you where you are, step by step. Some folks are very good at this, like twitter, but reality is that sometimes we don't even plan a keyboard only navigation in the first place.

So quick recap: we need a way to tell our keyboard people what elements they have focused in our app. Here is where our best buddy focus-visible selector came to play. Even well supported in modern browsers it's kinda new in the CSS playground. So we are going to set things up in the more compatible way.

OK let's make this happen !

You can find this repo at GitHub, feel free to clone it.
Also you can check the live version here .

I'm going to use Nuxt.js and Tailwind because those are my favorite tools, but you can apply what you will learn here to every project. The real hero behind the scenes here is the focus-visible Polyfill.

So create a new nuxt-app ( do not select tailwind yet):

npx create-nuxt-app focus-visible-sample
Enter fullscreen mode Exit fullscreen mode

Install Tailwind on your own:

cd focus-visible-sample
yarn add -D @nuxtjs/tailwindcss tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
Enter fullscreen mode Exit fullscreen mode

And install the polyfill and a postcss plugin to make it even easier to work with it:

yarn add focus-visible postcss-focus-visible
Enter fullscreen mode Exit fullscreen mode

Make sure to bundle the actual polyfill in your page.
Nuxt serves the static assets from the static folder off your project, so i will clone the polyfill file there in a scripts folder. You can find him at node_modules/focus-visible/dist/focus-visible.min.js. I also clone the .map version to avoid unuseful warnings in the browser developer console.
Do what you have to, i will use nuxt config file since he allows you declare metadata there super easy ( i 💚️ that framework) .

/* nuxt.config.js */

export default {
   head: {
       script: [
               { src: '/scripts/focus-visible.min.js', async: true, defer: true }
       ],
   }
}
Enter fullscreen mode Exit fullscreen mode

I will add the postcss plugin because I want to use it in conjunction with my tailwind utilities, but you will be just fine using the advice in the polyfill README.

I will add that plugin to my nuxt postcss config:

/*  nuxt.config.js  */
export default {
   // ...
   postcss:{
       plugins:{
           'postcss-focus-visible': {}
       }
   }
}
Enter fullscreen mode Exit fullscreen mode

We need to set up Tailwind too of course:

/*  nuxt.config.js  */
buildModules: [
    // https://go.nuxtjs.dev/tailwindcss
    '@nuxtjs/tailwindcss',
  ],
Enter fullscreen mode Exit fullscreen mode

Time to set up our Tailwind config:

npx tailwind init
Enter fullscreen mode Exit fullscreen mode

Since the 'focus-visible' variant is by default off we should manually get it on:
( I will be targeting the ring utility since that's the exact effect we want in our Ui)

/* tailwind.config.js  v2.x */

module.exports = {
   //...
   variants: {
       extend: {
           ringColor: ['focus-visible'],
       },
 },
}

Enter fullscreen mode Exit fullscreen mode

All setted up, let's do some pair programming !

In my home page (pages/index.vue) i have craft this form:

   <form class="mt-10 w-full max-w-sm" @submit.prevent="">
       <fieldset>
         <label for="petName" class="block ml-4">Pet Name</label>
         <input
           id="petName"
           type="text"
           placeholder="type your pet name here"
           class="block mt-2 px-4 py-2 w-full rounded-lg bg-gray-700 shadow-md focus:outline-none  focus:ring-2 focus:ring-indigo-600"
         />
       </fieldset>

       <div class="mt-6 w-full ">
         <button
           type="submit"
           class="py-2 w-full px-4 rounded-lg bg-indigo-700 hover:bg-indigo-800 shadow-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-400"
         >
           Get your Free Food
         </button>
       </div>
   </form>

Enter fullscreen mode Exit fullscreen mode

The App Screen Shot

Look closely.
In the input i have used the focus:outline-none utility to remove the default outline of the browser, if you aren't going to replace it, leave it there, it is better than nothing. Then I have used the focus:ring utility to show an enfasis for everyone, since it's a text input can be useful to show where we are going to write.
But for the submit button i have used the focus-visible utility instead, allowing us to render the rings only four our keyboard users, the ones that actually needed in this case. Check for yourself. There is no ring for the mouse submission. But if you hit the TAB you will see it. It's matching the default selector string that our focus-visible polyfill is expecting.

If you want to take a deep dive on accessibility i recommend chek this awesome resource. It’s a little extra work i will not lie to you. But I will make a tremendous impact on those users that need it; and often will improve the experience for everyone. Like those caption ready videos deliver the media for people can’t hear, but also for those that can’t understand that language. And if you want to go for a quality workshop about it, check “Accessibility in JavaScript Applications” by Marcy Sutton. That was the place where I started to learn this stuff in the first place. Thanks Marcy for introducing me to the a11y world.

That’s it my friend, go out there and craft good stuff. Your users will thank your hard work (even if they never sayit). If you have any doubts or want to say something, send me a tweet at @dagocarralero

Useful links

Nuxt docs
Tailwind docs
Focus Visible Repo
WebAim

Discussion (2)

Collapse
d4g0 profile image
d4g0 Author

Yeah that’s right, if you look out the repo you will find out there at the tailwind config. Now ( April 2021 ) with tailwind JIT you don’t even need to declare that anymore, a total game changer .