Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Create rule: no-visually-hidden-interactive-element #89

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/accessibility.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ linters:
enabled: true
GitHub::Accessibility::SvgHasAccessibleText:
enabled: true
GitHub::Accessibility::NoVisuallyHiddenInteractiveElements:
enabled: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# No visually hidden interactive elements

## Rule Details

This rule guards against visually hiding interactive elements. If a sighted keyboard user navigates to an interactive element that is visually hidden they might become confused and assume that keyboard focus has been lost.

Note: we are not guarding against visually hidden `input` elements at this time. Some visually hidden inputs might cause a false positive (e.g. some file inputs).

### Why do we visually hide content?

Visually hiding content can be useful when you want to provide information specifically to screen reader users or other assistive technology users while keeping content hidden from sighted users.

Applying the following css will visually hide content while still making it accessible to screen reader users.

```css
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
```

👎 Examples of **incorrect** code for this rule:

```jsx
<button className="sr-only">Submit</button>
```

👍 Examples of **correct** code for this rule:

```jsx
<h2 className="sr-only">Welcome to GitHub</h2>
```

## Version
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

require_relative "../../custom_helpers"

module ERBLint
module Linters
module GitHub
module Accessibility
class NoVisuallyHiddenInteractiveElements < Linter
include ERBLint::Linters::CustomHelpers
include LinterRegistry
INTERACTIVE_ELEMENTS = %w[a button summary select option textarea].freeze

MESSAGE = "Avoid visually hidding interactive elements. Visually hiding interactive elements can be confusing to sighted keyboard users as it appears their focus has been lost when they navigate to the hidden element"

def run(processed_source)
visually_hidden = false

tags(processed_source).each do |tag|
next if tag.closing?
classes = possible_attribute_values(tag, "class")
visually_hidden = true if classes.include?("sr-only")
next unless classes.include?("sr-only") || visually_hidden
if INTERACTIVE_ELEMENTS.include?(tag.name)
generate_offense(self.class, processed_source, tag)
end
end
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

require "test_helper"

class NoVisuallyHiddenInteractiveElements < LinterTestCase
def linter_class
ERBLint::Linters::GitHub::Accessibility::NoVisuallyHiddenInteractiveElements
end

def test_warns_if_element_is_interactive_and_visually_hidden
@file = "<button class='sr-only'>Text</button>"
@linter.run(processed_source)

assert_equal(1, @linter.offenses.count)
error_messages = @linter.offenses.map(&:message).sort
assert_match(/Avoid visually hidding interactive elements. Visually hiding interactive elements can be confusing to sighted keyboard users as it appears their focus has been lost when they navigate to the hidden element/, error_messages.last)
end

def test_does_not_warn_if_element_is_not_interactive_and_visually_hidden
@file = "<div class='sr-only'>Text</div>"
@linter.run(processed_source)

assert_empty @linter.offenses
end


def test_does_not_warn_if_element_is_interactive_and_not_visually_hidden
@file = "<button class='other'>Submit</button>"
@linter.run(processed_source)

assert_empty @linter.offenses
end

def test_does_not_warn_if_element_is_interactive_and_shown_on_focus
@file = "<a class='other show-on-focus'>skip to main content</a>"
@linter.run(processed_source)

assert_empty @linter.offenses
end

def test_warn_if_element_is_interactive_in_a_visually_hidden_parent
@file = "<div class='sr-only'><button>Submit</button></div>"
@linter.run(processed_source)

assert_equal(1, @linter.offenses.count)
error_messages = @linter.offenses.map(&:message).sort
assert_match(/Avoid visually hidding interactive elements. Visually hiding interactive elements can be confusing to sighted keyboard users as it appears their focus has been lost when they navigate to the hidden element/, error_messages.last)
end
end
4 changes: 2 additions & 2 deletions test/recommended_setup_works_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def test_asserts_recommended_setup_works
end
known_linter_names ||= ERBLint::LinterRegistry.linters.map(&:simple_name)

assert_equal 15, rules_enabled_in_accessibility_config
assert_equal 15, known_linter_names.count { |linter| linter.include?("GitHub::Accessibility") }
assert_equal 16, rules_enabled_in_accessibility_config
assert_equal 16, known_linter_names.count { |linter| linter.include?("GitHub::Accessibility") }
end
end