lfitzgibbons
lfitzgibbons

Reputation: 833

Making a clickable <div> accessible through tab structure?

So I am working on a project that requires a <div> with an onclick event. I've got the main functionality working, but there is one problem. I need the onclick event to happen when the user tabs to the <div> and presses enter. I added a tabindex to the <div> which allows it to gain focus, but nothing happens when the user presses enter (or any other key).

Can anyone help me with this? Or is what I want not even possible?

Here is a jsfiddle demonstrating my problem. http://jsfiddle.net/logiwan992/suwq7r09/

Thank you in advance for any help.

Upvotes: 39

Views: 72253

Answers (6)

user984003
user984003

Reputation: 29569

Give the element role="button" and tabindex="0" to make it focusable. Then detect an enter or space on any focused/active button. Turn that into a click.

Below is the html and jquery code for that. You only have to add this once and it works with all role=button elements.

<div role="button" tabindex="0">Do that thing</div>

$("body").on("keypress","[role='button']", function(e) { 
     if(e.keyCode == 13 || e.keyCode == 32){ // 13=enter, 32=spacebar
         $(this).click();
         return false;
     }
})

I actually do this instead of using a proper <button> element. It avoids having to deal with overriding browser button styles. It also seems quite common, for example look at Gmail; so many clickable icons and settings and navigation buttons, and not a <button> in sight.

Upvotes: 0

Daniel Beck
Daniel Beck

Reputation: 21495

I note the question is tagged WCAG and "accessibility".

The answer to your question is therefore "don't do that." The other answers on this page will all work fine, for everyone except the people who need it to work, i.e. those using screenreaders or other assistive technology. None of the javascript-based solutions here are WCAG compliant.

What you want is a <button>. That gives you your tabindex and keyboard control for free.

You can also force a <div> to work like a <button> by adding ARIA markup (though it's better and easier to just use the tag that already does what you need it to do.)

If absolutely necessary, a good introduction to using ARIA for pseudo-buttons is here: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role

The gist of it is, you need to add the role="button" attribute, and manage the state of the aria-pressed attribute manually (by capturing key events and clicks in javascript; other answers have covered this pretty thoroughly so I won't repeat the details)

Upvotes: 68

Adam
Adam

Reputation: 18855

The "onclick" attribute has a specific behavior on links, because it can be triggered with the enter key.

See the following WCAG failure: http://www.w3.org/TR/WCAG20-TECHS/F59.html

You have to take care of the "role" of the element.

The following page illustrates how you can make an "accessible link" from a "span": https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_link_role

Also, as already said, best way is relying on a button/a element when possible.

Upvotes: 1

slugolicious
slugolicious

Reputation: 17535

It is perfectly fine to have a <div> work like a button provided you specify the right ARIA tags, roles, and keyboard events. That's the whole point of ARIA.

I do agree, though, that when possible you should use the native html elements. That's the first rule of ARIA use - http://www.w3.org/TR/aria-in-html/#notes-on-aria-use-in-html. But I understand that's not always possible.

There was a mention of using focus(). That's incorrect. Focus() is used to move the focus to the object. It's not used to handle an event. Now perhaps they meant onFocus(), which is an event triggered when the object receives focus, but that's still not the right event to trap for. You don't want a button (whether implemented as a <div> or a <button>) to perform its function just because you tabbed to it. The user has to click or press enter/space on it.

Please look at the authoring practices which define the keyboard behavior for a button, http://www.w3.org/TR/wai-aria-practices/#button, as well as the section that talks about keyboard events, http://www.w3.org/TR/wai-aria-practices/#focus_tabindex. In particular, note that you should not rely on keypress. Not all browsers send that event.

Anytime you press a key, three possible events might happen: Keydown, keypress, keyup. Keydown and keyup are supported on all browsers and have access to event.keyCode. Keypress is supported on some browser and has access to event.charCode.

There's a significant different between keyCode and charCode, especially if you're trying to implement shortcut keys such as Ctrl+/. Many non-US keyboards have special keys in different places on the keyboard and you get different keyCodes for them. But that's a topic for another discussion.

Upvotes: 4

Jacob
Jacob

Reputation: 2164

Use the same event handler for both events. If the event is keypress verify the key pressed is the Enter key before executing.

var divButton = document.querySelector('#div-button');

divButton.addEventListener('click', activate);
divButton.addEventListener('keypress', activate);

function activate(e) {
  if (e.type === 'keypress' && e.keyCode == 13) {
    alert('activated the div'); 
  }
};
div {
    outline: 1px solid black;
}

div:focus {
    outline: 1px solid red;
}
<div id="div-button" tabindex="0">
    <h1>This is my div!</h1>
</div>    

Upvotes: -2

D4V1D
D4V1D

Reputation: 5849

Try to bind the keypress event on the said div and detect if Enter key was pressed (which has code number 13).

var div = document.getElementsByTagName('div');
div[0].addEventListener('keypress', function(e) {
    if(e.keyCode == 13) {
        alert('div focused');   
    }
});

Working JSFiddle


You can, alternatively, use jQuery also:

jQuery(function($) {

    $('div').on('keypress', function(e) {
        if(e.keyCode == 13) {
            alert('div focused'); 
        }
    });

});

Working JSFiddle

Upvotes: 1

Related Questions