Easy ARIA Tip #6: Making clickables accessible

It often happens that designers and web developers agree on the fact that they do not like the standard buttons or the styling capabilities of buttons in browsers. To work around this, they then resort to what’s called clickable text. It is in many cases a simple span or div element with some funky styling that makes it look like a button with some fancy twists. A JavaScript click handler then does the magic behind the scenes that happens if the user clicks on that particular styled text with the mouse.

Semantically, these styled text bits are totally meaningless to screen readers. The screen reader may or may not recognize that the text is clickable, but it can neither be tabbed to, nor is it known if this is a button, checkbox without a state that’s obvious, etc., etc.

Keyboard users also suffer from these, since these text bits are not tabable. Just adding an onclick handler does not automatically make these things focusable using the tab key.

Fortunately, there is WAI-ARIA. And with some simple additions to your markup, you can make these accessible and still profit from the fancy styling capabilities you get from using spans or divs instead of semantically correct buttons. Here’s the recipe:

Make it focusable

To do this, simply add the tabindex="0" bit to the span or div. Giving tabindex a value of 0 makes sure it fits into your tab order in the logical flow of your HTML code.

Make it a button

WAI-ARIA gives us the ability to tell assistive technologies such as screen readers for the blind that a certain element, or set of elements, actually means something that is not immediately obvious from the markup itself. In our case, even though the styling makes the span visually look like a button, the screen reader is not able to deduce that from the HTML and CSS instructions. To help it, you add role="button" to the element that receives the click. Ideally, this is the same that also already received the tabindex attribute above.

If it’s a graphic instead of text, also give it a label

Sometimes, you may end up with a clickable image instead of text. That’s fine, and both above parts of the recipe still apply, but in this case, and to be platform-independent, you should add aria-label="My button label" to the item. You can also do this with spans containing text if you want to be absolutely sure the screen reader speaks the right thing. aria-label takes a literal, and localizable, string as its value and translates that into the spoken label. Yes, for graphics, this even overrides the use of the alt attribute, if specified. And because some browser/screen reader combox like Safari and VoiceOver on the Mac have some problems with the alt attribute on occasion, aria-label puts you on the safe side.

Make Space and Enter activate the click handler

Yes, because this is no button in the original semantic sense, and browsers do not take into account WAI-ARIA markup except for when mapping stuff to the assistive technology APIs, you have to add a keypress handler that makes space and enter activate the onclick handler. In the regular desktop UI of most, if not all operating system, space is used to activate buttons, and enter is used to activate the default button of a dialog. But since in most cases we are not dealing with something that might have a default button except when it’s the submit button of a form, using enter in addition to space is OK here.

And that’s all there is to it! You need nothing more than that to make your fancy looking clickable buttons accessible on the basic level. Of course, if your button is a toggle and expands and collapses something, you may want to consider adding aria-expanded, as described in Easy ARIA Tip #5.

What about checkable clickables?

With a few tweaks, this will get you going as well:

  • Instead of “button”, use “checkbox” as the role, or “radiobutton”, if only one should be checked at a given time.
  • use aria-checked with a value of “true” for checked or “false” for non/checked items. In the same routine where you swap out the images to indicate the different states, also change the attribute or attributes accordingly. Make sure the attributes are never undefined, so are always either checked or not.
  • If dealing with radio buttons, enhance the onkeypress handler that reacts to the space bar and add support for arrows up and down to change focus to the next or previous radio buttons respectively. Tab should immediately jump to the next non-radio button outside that group of radio buttons.

These techniques can be used on both desktop and mobile. On mobile, you may want to react to touch events instead of click events, but I am sure you are already aware of that. 🙂

16 thoughts on “Easy ARIA Tip #6: Making clickables accessible

  1. Hi Marco,

    You say:

    You need nothing more than that to make your fancy looking clickable buttons accessible on the basic level.

    But Nicholas Zakas wrote an article recently called “You can’t create a button”, where he says:

    The enter key fires the click event when used on links and buttons by default. If you try to create your own button, as in the previous example, the enter key has no effect and therefore the user cannot perform that action.

    So if that technique (@role + @tabindex) does not make the element “clickable” via the enter key, how can it be called accessible?


  2. Thanks, it worked when I tried it earlier today on a sample page, but I will research this further. One might have to add a keyboard handler here as well, as I describe below your citation for check boxes. I will update the article if I find out why it worked for me but not for Nicholas. May be the screen reader simulating something that does not work if a screen reader isn’t active.


    1. Yes, I’d expect screen-readers to treat elements with role=”button” as if they were real buttons (with click and all), but that does not help many keyboard users out there.
      I believe that’s why you and Nicholas are experiencing different behaviors.


      1. Nicholas Zakas in his article meant that the CLICK event will not dispatch when you don’t use assistive technology. there is no argue that it would be better to use the correct UI elements but the WAI-ARIA come to help as in situations that you can not.


  3. Hi there
    Have not read through comments, so this may already have been pointed out, sorry.
    Isn’t there one step missing from your instructions for how to make a button clickable, keyboard listener.
    Once you add the tab index and role = button to the div or span you still have to make sure it reacts to a user pressing spacebar or enter, so you have to add a keyboard listened that listens for values 13 or 32 and executes the onclick event on onKeyDown, right? May be I am missing something, but can always benefit from learning a few things.
    Good blog, cool tips, keep it up!


  4. You will have to add a key handler for enter and/or space to work without a screen reader or when the screen reader is in forms/focus mode. When virtual cursor mode is on it will work with enter because the screen reader is calling the onclick event. But without a screen reader or in forms mode the keystroke is passed through to the browser and the browser does not translate enter or space into a click for divs, spans, etc.


  5. Thanks, all, for your feedback! I added a section on making the button executable via space and enter, and changed the note about the keyboard handler for radio buttons further below accordingly. Yes, I was indeed falling into the trap that screen readers tend to activate these even when in focus or forms mode, tricking me into believing that tabindex performs more magic than it does. 😉


  6. I think these techniques are great for quick fixes. The article by Zakas that Thierry pointed out “You can’t create a button” explains the best solution–use Anchors and Buttons.


  7. I guess the need for alt text should go without saying, but just in case:

    According to ARIA itself it’s a transitional mechanism, to help make up for missing features in underlying markup languages. Native markup like img alt should always be used when available. (Like the HTML5 nav w/ role=”navigation” case). So adding aria-label to help out defective implementations is great – exactly what it’s intended for. But it doesn’t remove the need for a non-empty img alt, which should be made consistent with aria.


  8. Nice post. Thanks.

    If you have to create a button item with a inner link (for settings or remove this item). How it’ll work ? I tried listbox role and options. I add link into options. It works fine with Jaws, NVDA but inner link is not read on iOS. Replacing option by group role seems to be better ….but it’s not correct has you said in your previous post. Another idea ?


  9. I have an scenario, I want to send focus to H1 [which is text element] when we click on a button, i am able to do it by adding tabindex = “-1”
    Problem, on Android with talkback screenreader, When focus goes to H1 [text] Talkback announces it as clickable element ie: [ Press ALT+Enter / double tab to activate ], h1 is text it cannot be text, is there any way to fix this?


    1. This is correct. By adding tabindex=”-1″, you make something focusable, which means it cfan also receive Onclick events, which means it is clickable. So, TalkBack behaves correctly in this case.


Share your thoughts

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.