/focus-visible-sample

A quick starter for apply `focus-visible` selector in your Nuxt projects.

Primary LanguageVue

title published description tags cover_image
true
A quick guide to setting up focus-visible on your nuxt/tailwind projects.
Nuxt,Tailwindcss, a11y

A quick guide to setting up focus-visible on your nuxt/tailwind projects.

Color Lights

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

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

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

yarn add focus-visible postcss-focus-visible

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 }
       ],
   }
}

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': {}
       }
   }
}

We need to set up Tailwind too of course:

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

Time to set up our Tailwind config:

npx tailwind init

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'],
       },
 },
}
 

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>
 

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