diff --git a/README.md b/README.md
index 2437185..f74d8b6 100644
--- a/README.md
+++ b/README.md
@@ -23,13 +23,20 @@ require "erblint-github/linters"
```yaml
---
linters:
+ GitHub::Accessibility::ImageHasAlt:
+ enabled: true
GitHub::Accessibility::NoRedundantImageAlt:
enabled: true
```
+### Rules
+
+- [GitHub::Accessibility::NoRedundantImageAlt](./docs/rules/accessibility/no-redundant-image-alt.md)
+- [GitHub::Accessibility::ImageHasAlt](./docs/rules/accessibility/image-has-alt.md)
+
## Testing
```
bundle install
-bundle exec rake test
+bundle exec rake
```
diff --git a/docs/rules/accessibility/image-has-alt.md b/docs/rules/accessibility/image-has-alt.md
new file mode 100644
index 0000000..e78c8dc
--- /dev/null
+++ b/docs/rules/accessibility/image-has-alt.md
@@ -0,0 +1,25 @@
+# Image Has Alt
+
+## Rule Details
+
+`
` should have an alt prop with meaningful text or an empty string for decorative images.
+
+Learn more at [W3C WAI Images Tutorial](https://www.w3.org/WAI/tutorials/images/).
+
+👎 Examples of **incorrect** code for this rule:
+
+```erb
+
+```
+
+👍 Examples of **correct** code for this rule:
+
+```erb
+
+
+```
+
+```erb
+
+
+```
diff --git a/docs/rules/accessibility/no-redundant-image-alt.md b/docs/rules/accessibility/no-redundant-image-alt.md
new file mode 100644
index 0000000..ee6f245
--- /dev/null
+++ b/docs/rules/accessibility/no-redundant-image-alt.md
@@ -0,0 +1,26 @@
+# No redundant image alt
+
+## Rule Details
+
+`
` alt prop should not contain `image` or `picture` as screen readers already announce the element as an image.
+
+Learn more at [W3C WAI Images Tutorial](https://www.w3.org/WAI/tutorials/images/).
+
+👎 Examples of **incorrect** code for this rule:
+
+```erb
+
+```
+
+👍 Examples of **correct** code for this rule:
+
+```erb
+
+
+```
+
+
+```erb
+
+
+```
diff --git a/lib/erblint-github/linters/github/accessibility/image_has_alt.rb b/lib/erblint-github/linters/github/accessibility/image_has_alt.rb
new file mode 100644
index 0000000..f72d66f
--- /dev/null
+++ b/lib/erblint-github/linters/github/accessibility/image_has_alt.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require_relative "../../custom_helpers"
+
+module ERBLint
+ module Linters
+ module GitHub
+ module Accessibility
+ class ImageHasAlt < Linter
+ include ERBLint::Linters::CustomHelpers
+ include LinterRegistry
+
+ MESSAGE = "
should have an alt prop with meaningful text or an empty string for decorative images"
+
+ def run(processed_source)
+ tags(processed_source).each do |tag|
+ next if tag.name != "img"
+ next if tag.closing?
+
+ alt = possible_attribute_values(tag, "alt")
+
+ generate_offense(self.class, processed_source, tag) if alt.empty?
+ end
+
+ rule_disabled?(processed_source)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/test/linters/accessibility/image_has_alt_test.rb b/test/linters/accessibility/image_has_alt_test.rb
new file mode 100644
index 0000000..4807c14
--- /dev/null
+++ b/test/linters/accessibility/image_has_alt_test.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require "test_helper"
+
+class ImageHasAltTest < LinterTestCase
+ def linter_class
+ ERBLint::Linters::GitHub::Accessibility::ImageHasAlt
+ end
+
+ def test_warns_if_image_has_no_alt_attribute
+ @file = "
"
+ @linter.run(processed_source)
+
+ refute_empty @linter.offenses
+ end
+
+ def test_does_not_warn_if_image_has_alt_attribute_set_to_empty_string
+ @file = "
"
+ @linter.run(processed_source)
+
+ assert_empty @linter.offenses
+ end
+
+ def test_does_not_warn_if_image_has_alt_attribute_set_to_string
+ @file = "
"
+ @linter.run(processed_source)
+
+ assert_empty @linter.offenses
+ end
+end