Eslint-plugin-jsx-a11y: No Static Element Interactions failing.

Created on 23 May 2017  Â·  19Comments  Â·  Source: jsx-eslint/eslint-plugin-jsx-a11y

I'm seeing the linter fail on this case, which I don't quite understand:

      <div
        {...this.props}
        role={this.props.role}
        onKeyPress={e => this.handleKeyPress(e)}
      >
        {this.props.children}
      </div>

Am I missing something, or is this a false positive? (FWIW, role has a default value of button, so unless someone were to be really explicitly bad, this should always have a reasonable role value.)

Most helpful comment

@ljharb, I am having the same issue as @Luchanso: the example doesn't pass when no-static-element-interactions is enabled; using the role attribute does not work.

All 19 comments

Yep, it's not work
I was try:

<div className="foo" onClick={() => {}} role="button" />

Everything should absolutely always be explicit - iow, you need to add role="button".

For your first example, why would there be a keypress inside a non-input element?
For your second example, why isn't that a <button> if you want it to be clickable?

For your first example, why would there be a keypress inside a non-input element?

The goal is to make an accessible button-like element, and not to use this for every case, only as necessary. In this case, the key handler mimics the standard button interactions. (and there are a few other properties in the component that I removed because they aren't essential in repro'ing this case). There are some situations where a button just doesn't seem to fit well, such as having something that has more complex children. While I agree that native elements are better (and I'm trying to use them to the extent that it's possible), isn't one of the goals of ARIA to be able to expose the same semantics to AT?

Everything should absolutely always be explicit - iow, you need to add role="button".

This is what the resulting markup is when rendered - but I thought (based on the docs) that when the role couldn't be inferred, but was set that the test should pass?

I took this example from your documentation

@cycomachead i'd love to hear some use cases; <button> can contain quite a bit of HTML.

@Luchanso are you saying that that example doesn't pass when no-static-element-interactions is enabled?

@cycomachead i'd love to hear some use cases; <button> can contain quite a bit of HTML.

Two cases:
1) buttons can't be nested. In one example I'm working with, there's a big selection area, and inside a smaller area that contains tags which can be removed.
2) Getting the "unstyling" of buttons to work consistently cross-browser can be challenging.

Anyway, doesn't the mere existence of the valid test cases for this rule prove there's a use case for a div with event handlers? In actual use the role with this div will almost always be "button", but it's a prop because there's a use for it being "checkbox" .

Nesting clickable things seems like an a11y and UX nightmare - it'd be really easy to accidentally click the wrong thing. Similarly, unstyling buttons means they don't look like buttons, which is also not a good thing (it's not that hard to reset buttons either).

I'll let other collabs weigh in on the OP.

@ljharb, I am having the same issue as @Luchanso: the example doesn't pass when no-static-element-interactions is enabled; using the role attribute does not work.

I don't really need judgements on this UX. :/ in the case of nested clickable elements, I agree it's not perfect but in the case the tap/click target sizes are large enough. In any event the paradigm of having 1 click region which contains smaller inset click regions that modify behavior or do something entirely different is rather common across the web and native platforms. Plus, a number of these design / tech requirements aren't mine, I'm just trying to make them as accessible as possible. And I have plans for even better accessible interfaces than we currently are building, but every project has its requirements and constraints.

In any case, I find this rule will helpful but it's frustrating if it's going to lead to false positives and confusing cases, which means it's more likely to be disabled on this project and that doesn't seem like a good outcome.

Do you agree there is a case for a div to be made to act like a button? If so,
that seems like what this rule is trying to help ensure. If not, then shouldn't the docs say "no matter what you can't have interactive handlers on static elements"?

--
Michael Ball
From my iPhone
michaelball.co

On May 24, 2017, at 11:44 AM, Dylan Frankland notifications@github.com wrote:

@ljharb, I am having the same issue as @Luchanso: the example doesn't pass when no-static-element-interactions is enabled; using the role attribute does not work.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

@cycomachead be careful putting anything but text or images. inside a button or an element with role="button". All of the content inside this element is squashed to text in the accessibility tree and becomes unavailable for interaction via assistive technology. Buttons should only content. Any interactive elements inside a button are lost.

<div className="foo" onClick={() => {}} role="button" />

This is passing in the text suite:

no-static-element-interactions

@Luchanso can you provide a little more context for where the rule is failing. Perhaps a large code snippet?

<div
    {...this.props}
    role={this.props.role}
    onKeyPress={e => this.handleKeyPress(e)}
  >
  {this.props.children}
</div>

@cycomachead We could certainly update the rule to allow a pass where the value of role cannot be determined. I'm half inclined to do that, I prefer clear failures to ambiguous ones. But I'm sensitive to @ljharb concerns that allowing a consumer of the component to vary the role prop value may lead to undesired results. A component shouldn't vary wildly in its semantics; it's either a button or a list item or a post, but it shouldn't be all these things. We don't allow child elements in our abstract button component at FB because it's too difficult to control. We expose three props: iconLeft, label and iconRight and limit the types with Flow. That's a button and there's very little else you can do with it.

If you need something to "catch clicks" you can put role="presentation" on a container and catch the bubbled events. Just make sure your controls have the right roles or are using semantic elements. =D

If others disagree with this, please leave your thoughts in further comments. We're all trying to figure this stuff out together.

I'm running into this too. I'm trying to come up with a failing test case but I can't get it to fail. Seems like the issue is more subtle. Here's the line in my code that's failing in case you have ideas about what the test case should include.

@adborden what version of the plugin are you using?

I'm using [email protected]

@adborden Version 6 might resolve the issues you're encountering.

Thanks, I'll try that out.

FYI, I had checked here https://github.com/evcohen/eslint-plugin-jsx-a11y/releases for a new version, so I thought I was using the latest.

Thanks, version 6 looks like it fixes the issue!

I'm getting an error on this rule, even when assigning a role. Using version 6.0.3.

image

Addressed with #572 by @markreay .

Was this page helpful?
0 / 5 - 0 ratings