Skip to content

Commit 89ff6e8

Browse files
authored
Merge pull request #11 from github/kh-avoid_both_disabled_and_aria_disabled
Add avoid both disabled and aria disabled rule
2 parents 8ba069b + c94f74c commit 89ff6e8

File tree

4 files changed

+103
-0
lines changed

4 files changed

+103
-0
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ require "erblint-github/linters"
2323
```yaml
2424
---
2525
linters:
26+
GitHub::Accessibility::AvoidBothDisabledAndAriaDisabled:
27+
enabled: true
2628
GitHub::Accessibility::ImageHasAlt:
2729
enabled: true
2830
GitHub::Accessibility::NoAriaLabelMisuse:
@@ -33,6 +35,7 @@ linters:
3335
3436
## Rules
3537
38+
- [GitHub::Accessibility::AvoidBothDisabledAndAriaDisabled](./docs/rules/accessibility/avoid-both-disabled-and-aria-disabled.md)
3639
- [GitHub::Accessibility::ImageHasAlt](./docs/rules/accessibility/image-has-alt.md)
3740
- [GitHub::Accessibility::NoAriaLabelMisuse](./docs/rules/accessibility/no-aria-label-misuse.md)
3841
- [GitHub::Accessibility::NoRedundantImageAlt](./docs/rules/accessibility/no-redundant-image-alt.md)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Avoid both disabled and aria disabled
2+
3+
## Rule Details
4+
5+
[From w3 ARIA in HTML ](https://www.w3.org/TR/html-aria/#docconformance-attr):
6+
> authors MAY use aria-disabled=true on a button element, rather than the disabled attribute. However, authors SHOULD NOT use both the native HTML attribute and the aria-* attribute together,
7+
8+
HTML elements with `disabled` are ignored when a screen reader uses tab navigation. To expose the disabled element, one may use `aria-disabled` and custom js and css to mimic disabled behavior *instead*. Setting both `aria-disabled` and `disabled` is unnecessary.
9+
10+
This linter will raise when both `aria-disabled` and `disabled` are set on HTML elements that natively support `disabled` including `button`, `fieldset`, `input`, `optgroup`, `option`, `select`, and `textarea`.
11+
12+
👎 Examples of **incorrect** code for this rule:
13+
14+
```erb
15+
<button aria-disabled="true" disabled="true">
16+
<input aria-disabled="true" disabled="true">
17+
```
18+
19+
👍 Examples of **correct** code for this rule:
20+
21+
```erb
22+
<button disabled="true">
23+
````
24+
25+
```erb
26+
<input disabled="true">
27+
```
28+
29+
```erb
30+
<button aria-disabled="true" class="js-disabled-button disabled-button">Update</button>
31+
```
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# frozen_string_literal: true
2+
3+
require_relative "../../custom_helpers"
4+
5+
module ERBLint
6+
module Linters
7+
module GitHub
8+
module Accessibility
9+
class AvoidBothDisabledAndAriaDisabled < Linter
10+
include ERBLint::Linters::CustomHelpers
11+
include LinterRegistry
12+
13+
ELEMENTS_WITH_NATIVE_DISABLED_ATTRIBUTE_SUPPORT = %w[button fieldset input optgroup option select textarea].freeze
14+
MESSAGE = "[aria-disabled] may be used in place of native HTML [disabled] to allow tab-focus on an otherwise ignored element. Setting both attributes is contradictory."
15+
16+
def run(processed_source)
17+
tags(processed_source).each do |tag|
18+
next if tag.closing?
19+
next unless ELEMENTS_WITH_NATIVE_DISABLED_ATTRIBUTE_SUPPORT.include?(tag.name)
20+
next unless tag.attributes["disabled"] && tag.attributes["aria-disabled"]
21+
22+
generate_offense(self.class, processed_source, tag)
23+
end
24+
25+
rule_disabled?(processed_source)
26+
end
27+
end
28+
end
29+
end
30+
end
31+
end
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# frozen_string_literal: true
2+
3+
require "test_helper"
4+
5+
class AvoidBothDisabledAndAriaDisabled < LinterTestCase
6+
def linter_class
7+
ERBLint::Linters::GitHub::Accessibility::AvoidBothDisabledAndAriaDisabled
8+
end
9+
10+
ELEMENTS_WITH_NATIVE_DISABLED_ATTRIBUTE_SUPPORT = %w[button fieldset input optgroup option select textarea].freeze
11+
12+
def test_warns_if_both_disabled_and_aria_disabled_set_on_html_elements_with_disabled_support
13+
@file = ELEMENTS_WITH_NATIVE_DISABLED_ATTRIBUTE_SUPPORT.map do |element|
14+
"<#{element} aria-disabled='true' disabled> </#{element}>"
15+
end.join
16+
@linter.run(processed_source)
17+
18+
assert_equal @linter.offenses.count, 7
19+
end
20+
21+
def test_does_not_warn_if_only_disabled_attribute_is_set
22+
@file = ELEMENTS_WITH_NATIVE_DISABLED_ATTRIBUTE_SUPPORT.map do |element|
23+
"<#{element} disabled> </#{element}>"
24+
end.join
25+
@linter.run(processed_source)
26+
27+
assert_empty @linter.offenses
28+
end
29+
30+
def test_does_not_warn_if_only_aria_disabled_attribute_is_set
31+
@file = ELEMENTS_WITH_NATIVE_DISABLED_ATTRIBUTE_SUPPORT.map do |element|
32+
"<#{element} aria-disabled='true'> </#{element}>"
33+
end.join
34+
@linter.run(processed_source)
35+
36+
assert_empty @linter.offenses
37+
end
38+
end

0 commit comments

Comments
 (0)