Search code examples
javascriptreactjsaccessibilitydecorator

Accessibility - React Ensure click events have key events


I want to be sure that all my onClick event are next to a onKeyDown event.

I will use eslint-plugin-jsx-a11y to ensure this. But in code, It is a way to do this generic. I mean, it will be annoying to do all the time:

 if(event.keyCode === 13){
    ...
 }

I would like to have a way to tell an element that in onKeyDown in case that the user use the execute the function in the onClick. Or a similar solution like http://www.karlgroves.com/2014/11/24/ridiculously-easy-trick-for-keyboard-accessibility/

In angular for instance, I have this clear. Let's go for a directive to do this automatically. But in React I don't know which is the best approach.


eslint rule: https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/click-events-have-key-events.md


Solution

  • Finally I only see 2 solutions:

    1 I can create a component that encapsulate all those actions... But this is the work of a button. And I want not to open a new way to create buttons in my project, this is just for exceptions and this can create a vicious behave inside the project. And for that we have another component... the button :)

    2 create a decorator for the actions.

    export function a11yButtonActionHandler(target, key, descriptor) {
        const fn = descriptor.value;
        if (typeof fn !== 'function') {
            throw new Error(`@a11yButtonActionHandler decorator can only be applied to methods not: ${typeof fn}`);
        }
    
        descriptor.value = function actionHandler(event) {
            if (!event || event.type === 'click' ||
                (['keydown', 'keypress'].includes(event.type) && ['Enter', ' '].includes(event.key))
            ) {
                fn.call(this, event);
            }
        };
    
        return descriptor;
    }
    

    and use the decorator.

    @a11yButtonActionHandler
    myAction(event) {
     ...
    }
    

    <div className="element-with-very-good-excuse-to-dont-be-a-button"
         role="button"
         tabIndex="0"
         onKeyDown={ this.myAction }
         onClick={ this.myAction }>