Accessibility - React Ensure click events have key events Accessibility - React Ensure click events have key events reactjs reactjs

Accessibility - React Ensure click events have key events


Another approach without decorators could be to use object spread to add the necessary props to an element:

function buttonize(handlerFn) {  return {    role: 'button',    onClick: handlerFn,    onKeyDown: event => {      // insert your preferred method for detecting the keypress      if (event.keycode === 13) handlerFn(event);    }  }}

and use like so:

<div  className="element-with-very-good-excuse-to-dont-be-a-button"  {...buttonize(this.myAction)}>click me</div>


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.

@a11yButtonActionHandlermyAction(event) { ...}

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


Great solutions here already, but I wanted an option where I didn't have to use decorators or prop-spreading. So I rejigged some of the existing answers into this:

function keyDownA11y(handler) {  return function onKeyDown(event) {    if (      ['keydown', 'keypress'].includes(event.type)      && ['Enter', ' '].includes(event.key)    ) {      handler();    }  }}

usage:

<div  onClick={myHandler}  onKeyDown={keyDownA11y(myHandler)}  role="button">  Hurray!</div>

EDIT: Alternatively, you could use this to make an A11yButton component and just import that. This way, you could get the benefits of cragb's excellent buttonizer solution:

import React from 'react';export default function A11yButton({  elementType,  onClick,  ...props}) {  return React.createElement(elementType, {    ...props,    onClick,    onKeyDown: keyDownA11y(onClick),    role: 'button',    // Add other props that might be necessary, like "tabIndex: 0,"  });}

Usage:

<A11yButton  elementType="div"  onClick={myHandler}>  Hurray!</A11yButton>