How to add a keyboard listener to my onClick handler?
Asked Answered
G

8

95

I have the following:

class MyTextArea extends React.Component {

  handleClick = () => {
    this.focus();
  }
    
  focus = () => this.ref.focus;

  handleRef = (component) => {
    this.ref = component;
  };

  render() {
    return (
      <div className="magicHelper" onClick={this.handleClick}>
        <textarea></textarea>
      </div>
    );
  }
}

My CSS:

.magicHelper {
  width: 100%;
  height: 100%;
}
textarea {
  line-height: 32px;
}

I need this because I need the textarea's placeholder to be horizontally and vertically centered in the page. Given textareas can't vertically center text, I need to keep the height of the textarea short. I therefore need to make it so that when the user clicks outside of the textarea, thinking they are clicking the textarea, the textarea auto focuses in.

This is causing an ESLint error:

"Visible, non-interactive elements with click handlers must have at least one keyboard listener".

How can I update the above to pass eslint?

Gleam answered 2/2, 2018 at 4:23 Comment(1)
In this specific example in the question, it actually is safe to just add an eslint-disable-next-line comment. This eslint rule exists to make sure your site is usable by people navigating with a screen reader + keyboard. The onClick handler in this question is there to solve a problem that only exists for people who are navigating the website using a mouse. Someone using a screen reader will be able to use the textarea with no issues, without any changes to this code. So the eslint rule can be ignored in this case.Uncommon
C
135

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

It seems this rule is to enforce Accessibility standards.

Based on this, change your code to do something like this

<div className="magicHelper" onClick={this.handleClick} onKeyDown={this.handleClick}>

You could also disable the rule in eslint, I suppose it depends on preference.

Clout answered 2/2, 2018 at 5:41 Comment(3)
how can we type this?Bunyabunya
In general, when making things clickable, one should simply use the correct element: A button. For this scenario it does not matter because there is a keyboard accessible element (the textarea), but this "solution" does nothing to help accessibility. The element is not focusable so it cannot receive keyboard events and it has no semantic role or title, so screen reader users would have no idea what they are dealing with.Accentuate
What about adding : tabIndex={0}Knutson
C
23

from ESLINT documents:

Enforce onClick is accompanied by at least one of the following: onKeyUp, onKeyDown, onKeyPress. Coding for the keyboard is important for users with physical disabilities who cannot use a mouse, AT compatibility, and screenreader users.

in this case you can either disable the rule or update your code. its better to update your code to meet the web standards.

 class MyTextArea extends React.Component {
    
      handleClick = () => {
        this.focus();
      }
      handleKeyDown = (ev) => {
          // check keys if you want
        if (ev.keyCode == 13) {
          this.focus()
         }
      }
      focus = () => this.ref.focus;
    
      handleRef = (component) => {
        this.ref = component;
      };
    
      render() {
        return (
          <div className="magicHelper" 
            onClick={this.handleClick} 
            onKeyDown={this.handleKeyDown}>
            <textarea></textarea>
          </div>
        );
      }
    }
Clarissaclarisse answered 2/2, 2018 at 6:24 Comment(0)
E
22

I got this kind of problem when committing the git message. I'm having following code at that time.

<span onClick={myHome}  className="home__home-header__mybb__mybb-links__ML1" >

to avoid it I used following attribute in the element.

aria-hidden="true"

Espouse answered 16/11, 2020 at 12:26 Comment(5)
But this way screen reader won't even get to know that there is. a button present. In these cases, we have to add a role as a button.Sip
@Kodali444, I was reading about aria-hidden, and was wondering if I would still retain my functionality of my div or button, right? it is just the accessibility features are disabled, right?Turd
Do not do this. This breaks your website for anyone using a screen reader.Uncommon
This is really bad approach. You should use aria-hidden="true" for elements you want to hide from screen reader. For example, if you got some info text, with some "i" icon, you can hide that "i" by adding taht attribute. You should use the right schemantic element for clickable items e.g button.Calvin
Your component became inaccessible.Knutson
C
10

You can pass the ESLint warning/error by adding at least one keyboard listener, as answered by Kaysser. But I'd rather fix the real problem here, which is having click and keyboard listeners on an element that's not recognised as clickable by browsers and screen readers.

The error message ("Visible, non-interactive elements with click handlers must have at least one keyboard listener") describes a lot when you think about it; you've added a click handler to an element that's made to display information and not for the user to interact with. On top of adding a keyboard listener you should also change the cursor to a pointer on hover, add tabindex, role etc. to make it accessible and comprehensible.

The best fix for this is to change the div element to a button, that solves the ESLint warning but also tells all browsers and screen readers that this is an interactive element that you can click with all kinds of pointers (mouse, keyboard, finger, stylus).

class MyTextArea extends React.Component {
  render() {
    return (
      <button className="magicHelper" onClick={this.handleClick}>
        <textarea></textarea>
      </button>
    );
  }
}

Did you make it to a div, span or any other element than a button because you didn't want the style of a button? It's better to remove that button-like styling and only make it look more like a div:

// CSS
.magicHelper {
  display: block;
  width: 100%;
  padding: 0;
  background-color: transparent;
  border: none;
  font: inherit;
  text-align: inherit;  
}
Catima answered 19/12, 2019 at 10:15 Comment(2)
I wish the linter notice would suggest "if you're trying to make a button just use a button"Xanthic
"change the div to a button" should be the top answer to this threadAnalysis
I
7

Indicate the element's role with the role, onKeyPress and tabIndex attributes:

<div
  onClick={onClickHandler}
  onKeyPress={onKeyPressHandler}
  role="button"
  tabIndex="0">
  Save
</div>
Indignity answered 16/8, 2021 at 8:7 Comment(1)
Adding these removed my warning. Thanks.Selenium
K
4

For those getting this error with the <img /> tag, you can replace it with the <input type="image" /> tag. So, change from:

<img alt="" src={} onClick={} />

to:

<input type="image" alt="" src={} onClick={} />
Kurus answered 22/6, 2021 at 2:43 Comment(0)
D
2

you can use onMouseDown instead of onClick

Devin answered 3/2, 2021 at 15:18 Comment(0)
L
1

For people who are unable or don't want to use a mouse, an onclick handler may not suffice. So ESLint tags this as an accessbility issue until you add an onKeyDown handler as well.

Leverhulme answered 18/6, 2021 at 20:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.