<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sandi Barr</title>
    <description>The latest articles on DEV Community by Sandi Barr (@sandikbarr).</description>
    <link>https://dev.to/sandikbarr</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F932794%2F76752ecd-8769-4a34-89cf-d831c6625efb.jpeg</url>
      <title>DEV Community: Sandi Barr</title>
      <link>https://dev.to/sandikbarr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sandikbarr"/>
    <language>en</language>
    <item>
      <title>Angular ESLint Rules for Accessible HTML Content</title>
      <dc:creator>Sandi Barr</dc:creator>
      <pubDate>Tue, 10 Jan 2023 19:14:04 +0000</pubDate>
      <link>https://dev.to/angular/angular-eslint-rules-for-accessible-html-content-kf5</link>
      <guid>https://dev.to/angular/angular-eslint-rules-for-accessible-html-content-kf5</guid>
      <description>&lt;p&gt;Content accessibility for built-in HTML elements is the third and final category in this series on Angular ESLint accessibility rules. These rules validate several HTML attributes that developers commonly overlook regarding accessibility. They check for alt text on images, accessible content in buttons, links, and headings, and proper form labels and table header associations. Angular ESLint accessibility rules provide immediate guidance on accessibility best practices right in the code, resulting in more accessible and user-friendly Angular applications.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Rules
&lt;/h1&gt;

&lt;p&gt;Previous articles in this series discussed how to add Angular ESLint and configure these rules in &lt;code&gt;.eslintrc.json&lt;/code&gt; config files, so let's get straight into the rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Alt Text&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@angular-eslint/template/accessibility-alt-text&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Elements Have Content&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@angular-eslint/template/accessibility-elements-content&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Label Has Associated Control&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@angular-eslint/template/accessibility-label-has-associated-control&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Table Scope&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@angular-eslint/template/accessibility-table-scope&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No Distracting Elements&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@angular-eslint/template/no-distracting-elements&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Button Has Type&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@angular-eslint/template/button-has-type&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Rule: Alt Text
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/accessibility-alt-text.md" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;@angular-eslint/template/accessibility-alt-text&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;accessibility-alt-text&lt;/code&gt; rule validates that all images have alternative text. Images must have an &lt;code&gt;alt&lt;/code&gt; attribute to meet &lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/non-text-content.html" rel="noopener noreferrer"&gt;WCAG 2.1 Success Criterion 1.1.1: Non-text Content&lt;/a&gt; that states all non-text content should have a text alternative that serves the equivalent purpose.&lt;/p&gt;

&lt;p&gt;Follow these guidelines for providing meaningful and concise &lt;code&gt;alt&lt;/code&gt; text:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alt text should express the relevant detail in an image to stand in for the same purpose, meaning, and intent.&lt;/li&gt;
&lt;li&gt;Alt text should not be redundant or repeat information from the image caption.&lt;/li&gt;
&lt;li&gt;Alt text should be short and to the point, ideally 150 characters or less.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When there is no &lt;code&gt;alt&lt;/code&gt; attribute on an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;, some screen readers will announce the image &lt;code&gt;src&lt;/code&gt; instead. Including an empty &lt;code&gt;alt&lt;/code&gt; attribute for decorative images indicates to screen readers that these images do not convey additional meaning or information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"decorative.gif"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to checking for the &lt;code&gt;alt&lt;/code&gt; attribute on &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; elements, the &lt;code&gt;accessibility-alt-text&lt;/code&gt; rule also validates &lt;code&gt;&amp;lt;input type="image"&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;area&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;object&amp;gt;&lt;/code&gt; elements, which support these attributes as alternative text:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;HTML element&lt;/th&gt;
&lt;th&gt;alternative text attributes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;alt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/image" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;input type="image"&amp;gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;alt&lt;/code&gt;, &lt;code&gt;aria-label&lt;/code&gt;, &lt;code&gt;aria-labelledby&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/area" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;area&amp;gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;alt&lt;/code&gt;, &lt;code&gt;aria-label&lt;/code&gt;, &lt;code&gt;aria-labelledby&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/object" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;object&amp;gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;aria-label&lt;/code&gt;, &lt;code&gt;aria-labelledby&lt;/code&gt;, &lt;code&gt;title&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Rule: Elements Have Content
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/accessibility-elements-content.md" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;@angular-eslint/template/accessibility-elements-content&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;accessibility-elements-content&lt;/code&gt; rule ensures that &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; - &lt;code&gt;&amp;lt;h6&amp;gt;&lt;/code&gt; elements have content. Screen readers announce these elements by their role and name (and level for headings.) Links, buttons, and headings are semantic elements with inherent meaning and implicit roles, and the &lt;a href="https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/" rel="noopener noreferrer"&gt;accessible name&lt;/a&gt; for these elements comes from their content, title, or aria-label.&lt;/p&gt;

&lt;p&gt;A button, link, or heading name may also come from a child element with plain text content, a title, or aria-label. Don't add redundant and unnecessary aria-labels where the accessible name comes from a child element. Use the &lt;a href="https://developer.chrome.com/docs/devtools/accessibility/reference/#pane" rel="noopener noreferrer"&gt;Accessibility pane in Chrome DevTools&lt;/a&gt; to inspect an element's computed name:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fze46w6rhfu4ze6otr0o3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fze46w6rhfu4ze6otr0o3.png" alt="Accessibility pane in Chrome DevTools showing button name computed from SVG title" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Rule: Label Has Associated Control
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/accessibility-label-has-associated-control.md" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;@angular-eslint/template/accessibility-label-has-associated-control&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The HTML &lt;a href="https://www.w3schools.com/tags/tag_label.asp" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt;&lt;/a&gt; element gives an accessible name to form controls. Labels are important for helping users understand the purpose of &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;output&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;meter&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;progress&amp;gt;&lt;/code&gt; elements.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A control can have more than one &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; cannot be associated with more than one control.&lt;/li&gt;
&lt;li&gt;Do not use &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; independently without an associated control.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; is associated with a form control with either an implicit or explicit association, and both styles are widely supported. Nesting a control inside &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; creates an &lt;strong&gt;implicit&lt;/strong&gt; association between the label and control:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Blue
&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whereas, assigning an &lt;code&gt;id&lt;/code&gt; to the control and using a matching &lt;code&gt;for&lt;/code&gt; attribute on the &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; creates an &lt;strong&gt;explicit&lt;/strong&gt; association:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"city"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;City&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"city"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;accessibility-label-has-associated-control&lt;/code&gt; rule determines if a label has an implicit association with a control nested inside the label or if the label has the &lt;code&gt;for&lt;/code&gt; attribute. The rule does not look elsewhere in the template for a control with an id matching the label's &lt;code&gt;for&lt;/code&gt; attribute and does not validate explicit label and control pairings. This is a natural limitation of static code analysis tools like Angular ESLint, so you’ll want to use additional testing techniques to validate the compiled application. The &lt;code&gt;for&lt;/code&gt; attribute could be a bound value, and Angular ESLint template rules do not validate bound values. Rules are generally limited to validating individual template nodes and their children, and the control could even be in another component's template separate from the label.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration Options for Label Has Associated Control
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;accessibility-label-has-associated-control&lt;/code&gt; rule supports the &lt;a href="https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/accessibility-label-has-associated-control.md#rule-options" rel="noopener noreferrer"&gt;configuration options&lt;/a&gt; &lt;code&gt;labelComponents&lt;/code&gt; and &lt;code&gt;controlComponents&lt;/code&gt;. The &lt;code&gt;labelComponents&lt;/code&gt; option adds validation for custom label components. The &lt;code&gt;controlComponents&lt;/code&gt; option configures the rule to recognize an implicit association on custom controls nested inside a label.&lt;/p&gt;

&lt;h4&gt;
  
  
  Option: Custom Label Components
&lt;/h4&gt;

&lt;p&gt;Configure &lt;code&gt;"labelComponents"&lt;/code&gt; for &lt;code&gt;"my-custom-label"&lt;/code&gt; with &lt;code&gt;"forControl"&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"@angular-eslint/template/accessibility-label-has-associated-control"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"labelComponents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"selector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-custom-label"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"inputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"forControl"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Validation on a custom label component to either require the &lt;code&gt;forControl&lt;/code&gt; input or to have a nested control:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-custom-label&lt;/span&gt; &lt;span class="na"&gt;forControl=&lt;/span&gt;&lt;span class="s"&gt;"myId"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Custom
&lt;span class="nt"&gt;&amp;lt;/my-custom-label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"myId"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;my-custom-label&amp;gt;&lt;/span&gt;
  Custom
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/my-custom-label&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Option: Custom Control Components
&lt;/h4&gt;

&lt;p&gt;Configure &lt;code&gt;"controlComponents"&lt;/code&gt; for &lt;code&gt;"my-custom-control"&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"@angular-eslint/template/accessibility-label-has-associated-control"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"controlComponents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"my-custom-control"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Validation on a custom control nested inside a label with an implicit association:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;
  Custom
  &lt;span class="nt"&gt;&amp;lt;my-custom-control&amp;gt;&amp;lt;/my-custom-control&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Rule: Table Scope
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/accessibility-table-scope.md" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;@angular-eslint/template/accessibility-table-scope&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;accessibility-table-scope&lt;/code&gt; rule validates the &lt;code&gt;scope&lt;/code&gt; attribute for table headers. The &lt;code&gt;scope&lt;/code&gt; attribute specifies which cells belong with a table header (&lt;code&gt;&amp;lt;th&amp;gt;&lt;/code&gt;.) Table header &lt;code&gt;scope&lt;/code&gt; accepts the following values: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;row&lt;/strong&gt;: associates a table header with all the cells in that row.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;col&lt;/strong&gt;: associates a table header with all the cells in that column.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;rowgroup&lt;/strong&gt;: associates a table header that spans multiple rows with all the cells in that row group.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;colgroup&lt;/strong&gt;: associates a table header that spans multiple columns with all the cells in that column group.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When table header scope is not specified, browsers and assistive technologies infer the relationship between table headers and their cells. Tables with headers in a single row or column do not need the &lt;code&gt;scope&lt;/code&gt; attribute. &lt;a href="https://www.w3.org/WAI/tutorials/tables/" rel="noopener noreferrer"&gt;More complex tables&lt;/a&gt; with irregular, multi-level, or both row and column headers should explicitly define which cells belong to which headers by using the &lt;code&gt;scope&lt;/code&gt; attribute on their table headers or the &lt;code&gt;id&lt;/code&gt; attribute on table headers with the &lt;code&gt;headers&lt;/code&gt; attribute on table cells.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rule: No Distracting Elements
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/no-distracting-elements.md" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;@angular-eslint/template/no-distracting-elements&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;no-distracting-elements&lt;/code&gt; rule disallows usage of the &lt;code&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;marquee&amp;gt;&lt;/code&gt; elements, which are both deprecated and no longer recommended for use.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; element is more than distracting. Flashing content can trigger seizures in people with photosensitive epilepsy. &lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/three-flashes-or-below-threshold.html" rel="noopener noreferrer"&gt;WCAG 2.1 Success Criterion 2.3.1&lt;/a&gt; dictates that there are no more than three flashes in a one second period or that the flash is below the threshold.&lt;/p&gt;

&lt;p&gt;The scrolling content in a &lt;code&gt;&amp;lt;marquee&amp;gt;&lt;/code&gt; element can create barriers for anyone who struggles with moving objects or people with cognitive disabilities like attention deficit disorder. &lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/pause-stop-hide.html" rel="noopener noreferrer"&gt;WCAG 2.1 Success Criterion 2.2.2&lt;/a&gt; states that users must be able to stop or hide any moving, blinking, scrolling, or auto-updating information.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bonus Rule: Button Has Type
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/button-has-type.md" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;@angular-eslint/template/button-has-type&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I mention this last rule as a bonus because it is not specifically an accessibility rule but is commonly missed and can lead to surprising functionality. The &lt;code&gt;button-has-type&lt;/code&gt; rule checks for the &lt;code&gt;type&lt;/code&gt; attribute on HTML &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; elements. A &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; inside a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; without a &lt;code&gt;type&lt;/code&gt; acts as a submit button and submits the form when pressed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Yes&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Submits the Form&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Not a Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"reset"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Resets the Form&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submits the Form&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  &lt;em&gt;That's All, Folks!&lt;/em&gt;
&lt;/h1&gt;

&lt;p&gt;The Angular ESLint rules covered in this series enable developers to create more accessible and user-friendly Angular applications by helping to ensure keyboard accessibility, ARIA compliance, and accessible HTML content. The &lt;a href="https://dev.to/angular/angular-eslint-rules-for-keyboard-accessibility-236f"&gt;first article&lt;/a&gt; discusses rules for ensuring that all interactive elements are reachable with a keyboard and that focus is not improperly managed. The &lt;a href="https://dev.to/angular/angular-eslint-rules-for-aria-3ba1"&gt;second article&lt;/a&gt; discusses Angular ESLint rules to check that ARIA roles have the required attributes and that ARIA attributes are valid. This third and final article discusses Angular ESLint rules to ensure accessible HTML content, such as image alt text, accessible names for form controls, buttons, links, and headings, and table heading scope. That covers all the rules pertaining to accessibility available with Angular ESLint.&lt;/p&gt;

&lt;p&gt;Static code analysis with Angular ESLint has the advantage of identifying issues early in development, but performing further automated and manual browser-based testing is essential for ensuring full accessibility. These Angular ESLint accessibility rules inspect individual nodes and elements used in the template code. It is also important to validate accessibility within the context of the entire application to check that headings are properly nested, that there are no nested interactive controls, that landmarks like &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;aside&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt; are used and labeled correctly, etc. Incorporating accessibility testing into each stage of the development and release process ensures that our Angular applications are usable by a wide range of users, including those with disabilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommended Testing Tools and Libraries:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/lighthouse/overview/#devtools" rel="noopener noreferrer"&gt;Lighthouse in Chrome DevTools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/devtools/accessibility/reference/#pane" rel="noopener noreferrer"&gt;Accessibility pane in Chrome DevTools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wave.webaim.org/extension/" rel="noopener noreferrer"&gt;WebAIM Wave Browser Extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chrome.google.com/webstore/detail/axe-devtools-web-accessib/lhdoppojpmngadmnindnejefpokejbdd" rel="noopener noreferrer"&gt;Axe DevTools Browser Extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://testing-library.com/docs/angular-testing-library/intro/" rel="noopener noreferrer"&gt;Angular Testing Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/dequelabs/axe-core-npm/blob/develop/packages/puppeteer/README.md" rel="noopener noreferrer"&gt;AxePuppeteer&lt;/a&gt; for Puppeteer&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/component-driven/cypress-axe" rel="noopener noreferrer"&gt;Cypress-axe library&lt;/a&gt; for Cypress&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;References:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/non-text-content.html" rel="noopener noreferrer"&gt;Understanding SC 1.1.1:Non-text Content (Level A)&lt;/a&gt; on W3C's Understanding WCAG 2.1&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/WAI/tutorials/images/decorative/" rel="noopener noreferrer"&gt;Decorative Images&lt;/a&gt; on W3C Web Accessibility Initiative&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/" rel="noopener noreferrer"&gt;Providing Accessible Names and Description&lt;/a&gt; on W3C Web Accessibility Initiative ARIA Authoring Practices Guide&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/WAI/tutorials/tables/" rel="noopener noreferrer"&gt;Tables Tutorial&lt;/a&gt; on W3C Web Accessibility Initiative&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/three-flashes-or-below-threshold.html" rel="noopener noreferrer"&gt;Understanding SC 2.3.1:Three Flashes or Below Threshold (Level A)&lt;/a&gt; on W3C's Understanding WCAG 2.1&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/pause-stop-hide.html" rel="noopener noreferrer"&gt;Understanding SC 2.2.2:Pause, Stop, Hide (Level A)&lt;/a&gt; on W3C's Understanding WCAG 2.1&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>angular</category>
      <category>a11y</category>
      <category>lint</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Angular ESLint Rules for ARIA</title>
      <dc:creator>Sandi Barr</dc:creator>
      <pubDate>Mon, 14 Nov 2022 15:16:34 +0000</pubDate>
      <link>https://dev.to/angular/angular-eslint-rules-for-aria-3ba1</link>
      <guid>https://dev.to/angular/angular-eslint-rules-for-aria-3ba1</guid>
      <description>&lt;p&gt;The acronym ARIA stands for &lt;strong&gt;A&lt;/strong&gt;ccessible &lt;strong&gt;R&lt;/strong&gt;ich &lt;strong&gt;I&lt;/strong&gt;nternet &lt;strong&gt;A&lt;/strong&gt;pplications. The purpose of ARIA is to make web content more accessible for people with disabilities. ARIA can enhance accessibility in custom-designed user interface controls and components, but incorrect use of ARIA can hinder accessibility and create a worse experience than no ARIA at all. Standard, semantic HTML components don't need ARIA to be accessible. As the saying goes, &lt;a href="https://www.w3.org/WAI/ARIA/apg/practices/read-me-first/" rel="noopener noreferrer"&gt;no ARIA is better than bad ARIA&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Advanced use of ARIA is a specific discipline that should be encapsulated into custom UI components that are used to create a consistent experience across an application. Creating such a reusable component library is a common practice in Angular development. Angular ESLint has rules for checking ARIA, but Angular does not add this validation out of the box. This post walks you through how to add Angular ESLint to a component library project, then dives deeper into the ARIA rules. I'll cover what each rule looks for in the Angular template code and how it uses the underlying libraries to validate ARIA roles and attributes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Angular ESLint to an Angular Library Project
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/angular/angular-eslint-rules-for-keyboard-accessibility-236f"&gt;previous post&lt;/a&gt; I covered how to add Angular ESLint to an Angular project. This post shows how to create an Angular library project with Angular ESLint support.&lt;/p&gt;

&lt;p&gt;To generate a new Angular workspace run the &lt;code&gt;ng new&lt;/code&gt; schematic without creating the default application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng new my-workspace --create-application false
cd my-workspace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add Angular ESLint to the workspace with the &lt;code&gt;ng add&lt;/code&gt; schematic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng add @angular-eslint/schematics  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate an Angular library using Angular ESLint's library schematic that runs the Angular library schematic under the hood then adds support for Angular ESLint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate @angular-eslint/schematics:lib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workspace will have both root and project level eslint configuration. The project &lt;code&gt;.eslintrc.json&lt;/code&gt; files extend from the root level config, so rules and their options can be set at the global level and added or overridden at the project level. Configure the ARIA template rules under "*.html" overrides:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1nq3x4uukqhts8r6axkz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1nq3x4uukqhts8r6axkz.png" alt="code editor showing eslint configuration" width="800" height="481"&gt;&lt;/a&gt;&lt;br&gt;Root and project level &lt;code&gt;.eslintrc.json&lt;/code&gt; config
  &lt;/p&gt;



&lt;br&gt;
Next let's take a deeper look at the two ARIA rules from Angular ESLint that are configured in the &lt;code&gt;.eslintrc.json&lt;/code&gt; above:

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Valid ARIA&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@angular-eslint/template/accessibility-valid-aria&lt;/code&gt;&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Role Has Required ARIA&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@angular-eslint/template/accessibility-role-has-required-aria&lt;/code&gt;&lt;/p&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Angular ESLint ARIA Rules
&lt;/h2&gt;

&lt;p&gt;The Angular ESLint ARIA rules run against Angular template code both inline and in separate template files and identify incorrect usage of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles" rel="noopener noreferrer"&gt;WAI-ARIA roles&lt;/a&gt; and their associated ARIA attributes. Ensuring &lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html" rel="noopener noreferrer"&gt;WAI-ARIA criteria&lt;/a&gt; are met enables user agents and assistive technologies to gather information about and interact with web content and controls.&lt;/p&gt;

&lt;p&gt;These rules originated from the &lt;a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y" rel="noopener noreferrer"&gt;eslint-plugin-jsx-a11y&lt;/a&gt; project and were ported over and implemented for Angular ESLint. Angular ESLint and eslint-plugin-jsx-a11y both use the &lt;a href="https://github.com/A11yance/aria-query" rel="noopener noreferrer"&gt;aria-query&lt;/a&gt; and &lt;a href="https://github.com/A11yance/axobject-query" rel="noopener noreferrer"&gt;axobject-query&lt;/a&gt; libraries to query information about ARIA roles and attributes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rule: Valid ARIA
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;@angular-eslint/template/accessibility-valid-aria&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;accessibility-valid-aria&lt;/code&gt; rule checks &lt;code&gt;aria-*&lt;/code&gt; attributes to be valid ARIA. The rule looks for HTML elements with bound or plain text ARIA attributes. Then it looks up the &lt;a href="https://github.com/A11yance/aria-query/blob/main/src/ariaPropsMap.js" rel="noopener noreferrer"&gt;ARIA property definition&lt;/a&gt; from the aria-query library to get the ARIA attribute value type and allowed values. &lt;/p&gt;

&lt;p&gt;If aria-query doesn’t have a definition for the matched ARIA attribute, the rule reports an invalid attribute value violation with the suggested fix to remove it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjut5snedknn95djm2vi7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjut5snedknn95djm2vi7.png" alt="code editor showing eslint violation" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;Violation of rule @angular-eslint/template/accessibility-valid-aria: The &lt;code&gt;aria-control&lt;/code&gt; is an invalid ARIA attribute
  &lt;/p&gt;

&lt;p&gt;If the ARIA attribute value is a literal value, it checks the value to be of the defined value type and one of the allowed values if provided. If the ARIA attribute value doesn’t match the ARIA property definition, the rule reports a violation that the attribute’s value is invalid:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1byik8yzrykxxxjj8tpa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1byik8yzrykxxxjj8tpa.png" alt="code editor showing eslint violation" width="800" height="468"&gt;&lt;/a&gt;&lt;br&gt;Violation of rule @angular-eslint/template/accessibility-valid-aria: The &lt;code&gt;aria-valuenow&lt;/code&gt; has an invalid value
  &lt;/p&gt;

&lt;p&gt;The template parser can only check the nodes and static values in the template itself, so a dynamically bound attribute value does not get flagged as a violation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxxo8s9qp7v37uueiw5f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxxo8s9qp7v37uueiw5f.png" alt="code editor with no eslint violations" width="800" height="468"&gt;&lt;/a&gt;&lt;br&gt;No violation on bound attribute value
  &lt;/p&gt;



&lt;h3&gt;
  
  
  Rule: Role Has Required ARIA
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;code&gt;@angular-eslint/template/accessibility-role-has-required-aria&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: You must be on at least version &lt;a href="https://github.com/angular-eslint/angular-eslint/blob/main/CHANGELOG.md#1420-2022-11-15" rel="noopener noreferrer"&gt;14.2.0&lt;/a&gt; of Angular ESLint to use the &lt;code&gt;accessibility-role-has-required-aria&lt;/code&gt; rule.&lt;/p&gt;

&lt;p&gt;This rule matches HTML elements with a plain text &lt;code&gt;role&lt;/code&gt; attribute and checks that the given role has the required ARIA attributes using the role definition from the aria-query library. For example, the &lt;a href="https://github.com/A11yance/aria-query/blob/main/src/etc/roles/literal/switchRole.js" rel="noopener noreferrer"&gt;switch role definition&lt;/a&gt; has one required property, aria-checked.&lt;/p&gt;

&lt;p&gt;Using role mappings from the axobject-query library, it determines if the HTML element's semantic role matches the given role. The &lt;code&gt;role="switch"&lt;/code&gt; can be applied to an &lt;code&gt;&amp;lt;input type="checkbox"/&amp;gt;&lt;/code&gt; and the required &lt;code&gt;aria-checked&lt;/code&gt; property is covered by the element’s semantic role. A &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; element does not have those same semantic properties and would be flagged as a violation if given the &lt;code&gt;role="switch"&lt;/code&gt; without &lt;code&gt;aria-checked&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp3yzpppyutwb0dz7cco0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp3yzpppyutwb0dz7cco0.png" alt="code editor showing eslint violation" width="800" height="461"&gt;&lt;/a&gt;&lt;br&gt;Violation of rule @angular-eslint/template/accessibility-role-has-required-aria: The span with role="switch" does not have required ARIA properties: aria-checked
  &lt;/p&gt;

&lt;p&gt;The complete set of roles with required ARIA properties covered by the &lt;code&gt;accessibility-role-has-required-aria&lt;/code&gt; rule is as follows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;WAI-ARIA role&lt;/th&gt;
&lt;th&gt;Required ARIA&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/A11yance/aria-query/blob/main/src/etc/roles/literal/checkboxRole.js" rel="noopener noreferrer"&gt;checkbox&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;aria-checked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/A11yance/aria-query/blob/main/src/etc/roles/literal/menuitemcheckboxRole.js" rel="noopener noreferrer"&gt;menuitemcheckbox&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;aria-checked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/A11yance/aria-query/blob/main/src/etc/roles/literal/menuitemradioRole.js" rel="noopener noreferrer"&gt;menuitemradio&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;aria-checked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/A11yance/aria-query/blob/main/src/etc/roles/literal/radioRole.js" rel="noopener noreferrer"&gt;radio&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;aria-checked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/A11yance/aria-query/blob/main/src/etc/roles/literal/switchRole.js" rel="noopener noreferrer"&gt;switch&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;aria-checked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/A11yance/aria-query/blob/main/src/etc/roles/literal/headingRole.js" rel="noopener noreferrer"&gt;heading&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;aria-level&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/A11yance/aria-query/blob/main/src/etc/roles/literal/optionRole.js" rel="noopener noreferrer"&gt;option&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;aria-selected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/A11yance/aria-query/blob/main/src/etc/roles/literal/treeitemRole.js" rel="noopener noreferrer"&gt;treeitem&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;aria-selected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/A11yance/aria-query/blob/main/src/etc/roles/literal/comboboxRole.js" rel="noopener noreferrer"&gt;combobox&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;aria-controls &lt;br&gt; aria-expanded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/A11yance/aria-query/blob/main/src/etc/roles/literal/meterRole.js" rel="noopener noreferrer"&gt;meter&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;aria-valuenow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/A11yance/aria-query/blob/main/src/etc/roles/literal/sliderRole.js" rel="noopener noreferrer"&gt;slider&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;aria-valuenow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/A11yance/aria-query/blob/main/src/etc/roles/literal/scrollbarRole.js" rel="noopener noreferrer"&gt;scrollbar&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;aria-controls &lt;br&gt; aria-valuenow&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Suggestion for Adoption
&lt;/h2&gt;

&lt;p&gt;Enabling Angular ESLint's accessibility rules all at once in a codebase with existing accessibility issues can produce a long list of violations that might initially seem overwhelming and difficult to prioritize. Enable these sets of rules incrementally to tackle one category at a time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keyboard Accessibility&lt;/strong&gt;&lt;br&gt;
All content and functionality must be usable with the keyboard. Keyboard access is essential for assistive technologies and should be a top priority. The article in this series on &lt;a href="https://dev.to/angular/angular-eslint-rules-for-keyboard-accessibility-236f"&gt;Angular ESLint Rules for Keyboard Accessibility&lt;/a&gt; covers the lint rules that can help. You won't be able to automate validation of all keyboard functionality with lint rules or automated testing. Be sure to incorporate &lt;a href="https://www.w3.org/WAI/test-evaluate/preliminary/#interaction" rel="noopener noreferrer"&gt;manual interaction testing&lt;/a&gt; into your process to ensure a logical focus order is maintained along with a visible focus ring.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ARIA Roles and Attributes&lt;/strong&gt;&lt;br&gt;
Providing accessible components from a shared library helps standardize your approach to UI/UX and accessibility across your application(s). Isolate most ARIA to your custom UI components and use Angular ESLint's ARIA rules to validate best practices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Content and Relationships&lt;/strong&gt;&lt;br&gt;
These rules ensure accessibility for non-text content and content relationships in forms and tables. Alternative text should convey the purpose and context for non-text content. Ensuring content accessibility also requires human input and manual review to make sure the content is meaningful and presented consistently. Stay tuned for my last article in this series about the Angular ESLint Accessibility Rules for Content and Relationships.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;



&lt;h2&gt;
  
  
  But Wait, There's More? There Sure Could Be
&lt;/h2&gt;

&lt;p&gt;The eslint-plugin-jsx-a11y library, where these Angular ESLint ARIA rules originate, has even more rules for validating ARIA that could be borrowed from and added to Angular ESLint. These rule additions could also leverage aria-query and axobject-query to validate ARIA usage and encourage better practices with semantic HTML.&lt;/p&gt;

&lt;h3&gt;
  
  
  Even More ARIA Rules in eslint-plugin-jsx-a11y
&lt;/h3&gt;

&lt;p&gt;I would also like to implement these rules for Angular ESLint:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-role.md" rel="noopener noreferrer"&gt;&lt;code&gt;aria-role&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Elements with ARIA roles must use a valid, non-abstract ARIA role.&lt;/em&gt;&lt;br&gt;
Valid ARIA roles must be used in order for user agents to understand and interact with those elements according to specifications. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles#6._abstract_roles" rel="noopener noreferrer"&gt;Abstract roles&lt;/a&gt; are the foundational roles upon which other WAI-ARIA roles are built and organized and are not to be used directly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/role-supports-aria-props.md" rel="noopener noreferrer"&gt;&lt;code&gt;role-supports-aria-props&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Enforce that elements with explicit or implicit roles defined contain only &lt;code&gt;aria-*&lt;/code&gt; properties supported by that role.&lt;/em&gt;&lt;br&gt;
It does no good to add ARIA attributes to elements with roles that don't support those attributes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-aria-hidden-on-focusable.md" rel="noopener noreferrer"&gt;&lt;code&gt;no-aria-hidden-on-focusable&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Enforce that &lt;code&gt;aria-hidden="true"&lt;/code&gt; is not set on focusable elements.&lt;/em&gt;&lt;br&gt;
Using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-hidden" rel="noopener noreferrer"&gt;aria-hidden&lt;/a&gt; hides an element and its children from the accessibility API. Elements that aren't accessible to assistive technologies should not be able to receive focus via keyboard.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-interactive-element-to-noninteractive-role.md" rel="noopener noreferrer"&gt;&lt;code&gt;no-interactive-element-to-noninteractive-role&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ARIA roles should not be used to convert an interactive element to a non-interactive element.&lt;/em&gt;&lt;br&gt;
This rule prevents interactive elements meant as controls from being assigned non-interactive roles meant for content or containers. A content role such as &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/meter_role" rel="noopener noreferrer"&gt;meter&lt;/a&gt;, for example, could not be assigned to an &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-noninteractive-element-to-interactive-role.md" rel="noopener noreferrer"&gt;&lt;code&gt;no-noninteractive-element-to-interactive-role&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ARIA roles should not be used to convert a non-interactive element to an interactive element.&lt;/em&gt;&lt;br&gt;
Elements meant for content or containers, such as &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;, should not be assigned interactive roles meant for controls such as the button or checkbox roles.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-redundant-roles.md" rel="noopener noreferrer"&gt;&lt;code&gt;no-redundant-roles&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ARIA roles should not redundantly match an element's default/implicit role already set by the browser.&lt;/em&gt;&lt;br&gt;
An &lt;code&gt;&amp;lt;input type="checkbox"&amp;gt;&lt;/code&gt; element already has the implicit role checkbox, so adding &lt;code&gt;role="checkbox"&lt;/code&gt; would be redundant.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/prefer-tag-over-role.md" rel="noopener noreferrer"&gt;&lt;code&gt;prefer-tag-over-role&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Enforces using semantic DOM elements over the ARIA role property.&lt;/em&gt;&lt;br&gt;
This rule prevents content or container elements like &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; from being assigned roles like &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/banner_role" rel="noopener noreferrer"&gt;banner&lt;/a&gt; or &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/heading_role" rel="noopener noreferrer"&gt;heading&lt;/a&gt; where a built-in, semantic HTML element is preferable.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🎉 Shout out in the comments if you think having these rules in Angular ESLint would improve accessibility practices in your Angular codebase!&lt;/p&gt;




&lt;br&gt;&lt;br&gt;
&lt;strong&gt;References:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/WAI/ARIA/apg/practices/read-me-first/" rel="noopener noreferrer"&gt;ARIA Authoring Practices Guide&lt;/a&gt; on W3C Web Accessibility Initiative&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/WAI/test-evaluate/preliminary" rel="noopener noreferrer"&gt;Easy Checks – A First Review of Web Accessibility&lt;/a&gt; on W3C Web Accessibility Initiative&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles" rel="noopener noreferrer"&gt;WAI-ARIA roles&lt;/a&gt; on MDN&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html" rel="noopener noreferrer"&gt;Understanding Success Criterion 4.1.2: Name, Role, Value&lt;/a&gt; on W3C's Understanding WCAG 2.1&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y" rel="noopener noreferrer"&gt;eslint-plugin-jsx-a11y&lt;/a&gt; on GitHub&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/A11yance/aria-query" rel="noopener noreferrer"&gt;aria-query&lt;/a&gt; on GitHub&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/A11yance/axobject-query" rel="noopener noreferrer"&gt;axobject-query&lt;/a&gt; on GitHub&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>angular</category>
      <category>a11y</category>
      <category>lint</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Angular ESLint Rules for Keyboard Accessibility</title>
      <dc:creator>Sandi Barr</dc:creator>
      <pubDate>Fri, 14 Oct 2022 13:20:22 +0000</pubDate>
      <link>https://dev.to/angular/angular-eslint-rules-for-keyboard-accessibility-236f</link>
      <guid>https://dev.to/angular/angular-eslint-rules-for-keyboard-accessibility-236f</guid>
      <description>&lt;p&gt;When using built-in HTML elements, the browser provides proper and expected keyboard support out of the box. Users can tab to a form input, use arrow keys to navigate through options in a select, or press a button with the Spacebar or Enter key. The recommended practice is to use semantic HTML elements and rely on the browser's built-in affordances for keyboard accessibility. Still, this advice is frequently not followed in favor of custom designed elements. Instead of using a button, developers sometimes add a click event to a span or div without realizing their implementation is not accessible to keyboard users. Ensuring accessible keyboard navigation also enables users of assistive technologies like &lt;a href="https://axesslab.com/switches/" rel="noopener noreferrer"&gt;switch devices&lt;/a&gt; to interact with your application. Angular ESLint's accessibility rules can catch some of these common keyboard navigation pitfalls and provide helpful and immediate feedback on Angular template code both inline and in separate template files.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Get Angular ESLint
&lt;/h2&gt;

&lt;p&gt;If you're not already using &lt;a href="https://github.com/angular-eslint/angular-eslint" rel="noopener noreferrer"&gt;Angular ESLint&lt;/a&gt;, you can add it to an Angular project by running the schematic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng add @angular-eslint/schematics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The schematic adds a target to angular.json that enables the lint command on the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng lint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure the rules in the  .eslintrc.json file under "*.html" overrides:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70cyjdao7vnk4db3g0pc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70cyjdao7vnk4db3g0pc.png" width="800" height="470"&gt;&lt;/a&gt;&lt;br&gt;ESLint template rule configuration in .eslintrc.json
  &lt;/p&gt;




&lt;p&gt;Read on to learn more about the accessibility guidelines and best practices behind each of these rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rules for Accessible Keyboard Navigation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  No Positive Tab Index
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;@angular-eslint/template/no-positive-tabindex&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/focus-order.html" rel="noopener noreferrer"&gt;WCAG Success Criterion 2.4.3 Focus Order&lt;/a&gt; dictates that elements on the page should receive focus in a sequential order that is meaningful to the content. The tab order should flow through the page from the header and navigation, through the main content, end at the footer, and circle back around. Built-in HTML elements that support interactive behaviors can be navigated to and receive focus by tabbing through the page.&lt;/p&gt;

&lt;p&gt;Generally, the &lt;code&gt;tabindex&lt;/code&gt; attribute isn't needed for buttons, links, and form controls. Assigning tabindex adds focus support to an element that can't otherwise receive focus. A tabindex greater than zero inserts elements into the focus order before elements without a tabindex or a tabindex of zero. A tabindex of -1 is a particular case that takes elements out of the focus order but allows them to receive focus programmatically. Enable the &lt;code&gt;no-positive-tabindex&lt;/code&gt; rule to prevent usage of tabindex values other than 0 or -1.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Autofocus
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;@angular-eslint/template/no-autofocus&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;no-autofocus&lt;/code&gt; rule discourages use of the &lt;code&gt;autofocus&lt;/code&gt; attribute. Using autofocus can cause screen readers to jump to a control without context and break the expected tab navigation flow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mouse Events Have Key Events
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;@angular-eslint/template/mouse-events-have-key-events&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;All content must be accessible with the keyboard alone. For example, if mousing over an element reveals additional content, there should be consideration for keyboard users who may navigate via tab to focus the trigger. The &lt;code&gt;mouse-events-have-key-events&lt;/code&gt; rule ensures that elements with &lt;code&gt;(mouseover)&lt;/code&gt; or &lt;code&gt;(mouseout)&lt;/code&gt; event handlers also have corresponding keyboard support with &lt;code&gt;(focus)&lt;/code&gt; or &lt;code&gt;(blur)&lt;/code&gt;. Enabling this rule assists with following the WCAG technique &lt;a href="https://www.w3.org/TR/WCAG20-TECHS/SCR2.html" rel="noopener noreferrer"&gt;SCR2: Using redundant keyboard and mouse event handlers&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Click Events Have Key Events
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;@angular-eslint/template/click-events-have-key-events&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Wherever users can click, they should also be able to access via keyboard. The &lt;code&gt;click-events-have-key-events&lt;/code&gt; rule ensures that elements with &lt;code&gt;(click)&lt;/code&gt; event handlers also have at least one accompanying keyboard event, meaning &lt;code&gt;(keyup)&lt;/code&gt;, &lt;code&gt;(keydown)&lt;/code&gt;, &lt;code&gt;(keypress)&lt;/code&gt;, or a key filtered variation like &lt;code&gt;(keyup.enter)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;click-events-have-key-events&lt;/code&gt; eslint rule violation appears when developers use a &lt;code&gt;(click)&lt;/code&gt; event on an element that is not interactive by default and does not have built-in keyboard accessibility. For example, adding &lt;code&gt;(click)&lt;/code&gt; to a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; or a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; to act like a button is not a button. A &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; does not need key events added because the browser triggers the click event with the Spacebar or Enter key.&lt;/p&gt;

&lt;p&gt;Anchor elements (&lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;) with &lt;code&gt;(click)&lt;/code&gt; events that don't have an &lt;code&gt;href&lt;/code&gt; or &lt;code&gt;routerLink&lt;/code&gt; also violate this rule. Anchor links must include the &lt;code&gt;href&lt;/code&gt; attribute for built-in accessibility and keyboard support. If an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; has &lt;code&gt;(click)&lt;/code&gt; and no &lt;code&gt;href&lt;/code&gt;, should it instead be a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;? Links and buttons are semantically different. Buttons are meant to do something within the view; whereas, links are for navigation to a different view or page (one exception being download links.)&lt;/p&gt;

&lt;p&gt;Here's what this rule violation looks like with the &lt;a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint" rel="noopener noreferrer"&gt;ESLint extension&lt;/a&gt; enabled in VS Code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F21isoq6229xkupm43ype.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F21isoq6229xkupm43ype.png" width="800" height="398"&gt;&lt;/a&gt;&lt;br&gt;Violation of rule @angular-eslint/template/click-events-have-key-events: click must be accompanied by either keyup, keydown or keypress event for accessibility.
  &lt;/p&gt;




&lt;p&gt;Another thing to consider is that key event handlers on an element can only be triggered when that element has focus. When used on its own, the &lt;code&gt;click-events-have-key-events&lt;/code&gt; rule could encourage developers to add a key event to elements that do not have native keyboard support and may not actually receive focus via tabbing. How do we confirm these custom elements we intend to work with both the mouse and keyboard can also receive focus?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;interactive-supports-focus enters the chat...&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessibility Interactive Supports Focus
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;@angular-eslint/template/accessibility-interactive-supports-focus&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: You must be on at least version &lt;a href="https://github.com/angular-eslint/angular-eslint/blob/main/CHANGELOG.md#1420-2022-11-15" rel="noopener noreferrer"&gt;14.2.0&lt;/a&gt; of Angular ESLint to use the &lt;code&gt;accessibility-interactive-supports-focus&lt;/code&gt; rule.&lt;/p&gt;

&lt;p&gt;The intent of &lt;code&gt;accessibility-interactive-supports-focus&lt;/code&gt; is to verify that HTML elements with interaction handlers (click, keydown, keyup, keypress) can receive focus either because the element is interactive by default (like a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;, etc.) or by adding a tabindex to the element. When using tabindex, you'll also want to check your templates against that &lt;code&gt;no-positive-tabindex&lt;/code&gt; rule mentioned previously. These keyboard navigation rules work in conjunction with each other to facilitate the development of accessible web applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part of a "Complete Breakfast"
&lt;/h2&gt;

&lt;p&gt;Applying these rules with Angular ESLint can give developers immediate feedback on their template code and identify problems early in development. However, the lint checks are limited to the precompiled template nodes and static values. These template rules only apply to what's in the template, so they also cannot check Angular Component host properties or HostBindings for bound attributes. Browser-based testing tools that run against compiled application code do a more thorough evaluation by validating elements in relationship to each other and within the entire page. Use a combination of automated and manual accessibility testing alongside Angular ESLint for more thorough accessibility checks on your Angular applications.&lt;/p&gt;

&lt;p&gt;Stay tuned for my next post on &lt;a href="https://dev.to/angular/angular-eslint-rules-for-aria-3ba1"&gt;Angular ESLint Rules for ARIA&lt;/a&gt; (Accessible Rich Internet Applications)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://webaim.org/techniques/keyboard/" rel="noopener noreferrer"&gt;Keyboard Accessibility&lt;/a&gt; on WebAIM&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://axesslab.com/switches/" rel="noopener noreferrer"&gt;Assistive Technologies – The Switch&lt;/a&gt; on Axess Lab&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/focus-order.html" rel="noopener noreferrer"&gt;WCAG Success Criterion 2.4.3 Focus Order&lt;/a&gt; on W3C's Understanding WCAG 2.1&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/WAI/WCAG21/Techniques/client-side-script/SCR2" rel="noopener noreferrer"&gt;SCR2: Using redundant keyboard and mouse event handlers&lt;/a&gt; on W3C's Techniques for WCAG 2.1&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://marcysutton.com/links-vs-buttons-in-modern-web-applications" rel="noopener noreferrer"&gt;Links vs. Buttons in Modern Web Applications&lt;/a&gt; on MarcySutton.com&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>angular</category>
      <category>a11y</category>
      <category>lint</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
