<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Elizabeth Lola - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Elizabeth Lola - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 22:19:53 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/elizabethmeshioye/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Use CSS to Improve Web Accessibility ]]>
                </title>
                <description>
                    <![CDATA[ Did you know that CSS can play a significant role in web accessibility? While CSS primarily handles the visual presentation of a webpage, when you use it properly it can enhance the user’s experience and improve accessibility. In this article, I'll s... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-css-to-improve-web-accessibility/</link>
                <guid isPermaLink="false">66eb0a282e5bd4267b92ca10</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ frontend ]]>
                    </category>
                
                    <category>
                        <![CDATA[ a11y ]]>
                    </category>
                
                    <category>
                        <![CDATA[ webdev ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Design ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabeth Lola ]]>
                </dc:creator>
                <pubDate>Wed, 18 Sep 2024 17:13:12 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726577970240/02631676-6492-4b83-a057-b9c2048709ee.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Did you know that CSS can play a significant role in web accessibility? While CSS primarily handles the visual presentation of a webpage, when you use it properly it can enhance the user’s experience and improve accessibility.</p>
<p>In this article, I'll share some ways CSS can support accessibility so you can start using these techniques in your own projects.</p>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>To follow along with this tutorial, you should have a basic understanding of HTML, CSS, and a little bit of Javascript.</p>
<h2 id="heading-update-focus-styles">Update Focus Styles</h2>
<p>The browser provides default focus styles for interactive elements like buttons or input fields. But sometimes these default focus styles might not be ideal for your design system – especially if the colors used in your design are too close to the default colors. This might make it difficult to notice.</p>
<p>Also, different browsers have different default focus styles and you might want to standardize the focus styles to ensure uniformity.</p>
<p>You can change the default focus style of an element in CSS using the <code>:focus</code> pseudo-class. For example, the default focus style for an input element is a blue outline in Chrome and a blue outline with outline offset in Firefox, to update the default focus styles of an input element you can do this:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">input</span><span class="hljs-selector-pseudo">:focus</span> {
  <span class="hljs-attribute">outline</span>: <span class="hljs-number">2px</span> solid <span class="hljs-number">#007BFF</span>;
  <span class="hljs-attribute">outline-offset</span>: <span class="hljs-number">2px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">1rem</span>;
}
</code></pre>
<h2 id="heading-avoid-content-shifts">Avoid Content Shifts</h2>
<p>Content shifts can happen when you’re lazy loading images, where images load progressively as the user scrolls down the page. Sometimes the image pushes the content around it downwards, shifting the text you're reading out of place.</p>
<p>Content shifts can also happen during dynamic content fetching, especially when new content like text, images, or ads is added to the page without reserving space for it in advance.</p>
<p>Content shifts can be frustrating, especially for users:</p>
<ul>
<li><p>With cognitive disabilities who may lose track of where they are in the content.</p>
</li>
<li><p>Using screen magnifiers, where the shift can cause them to lose their zoomed-in focus.</p>
</li>
<li><p>Navigating with a keyboard, as it can mess up the natural tab order and make navigation confusing.</p>
</li>
</ul>
<p>You can pre-allocate space for content to prevent shifts by using the <code>min-height</code> or <code>aspect-ratio</code> properties. Here's how you can allocate space for an image to prevent content shift before the image has fully loaded.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">img</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">height</span>: auto;
    <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">16</span>/<span class="hljs-number">9</span>;
    <span class="hljs-attribute">object-fit</span>: cover; <span class="hljs-comment">/* Ensures the image fits well within the allocated space */</span>
}
</code></pre>
<p>You can also use animations or transitions when dynamically loading content to add smooth transitions for new content. So, instead of a sudden shift, the content slides in gracefully, reducing the perception of disruption.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.new-content</span> {
    <span class="hljs-attribute">transition</span>: margin <span class="hljs-number">0.3s</span> ease-in-out, opacity <span class="hljs-number">0.3s</span> ease-in-out;
}
</code></pre>
<h2 id="heading-reduce-motion">Reduce Motion</h2>
<p>Rapid animations or really complex transitions can be disorienting for users with motion sensitivity, which could lead to discomfort like headaches, dizziness, or vertigo (for users with vestibular disorders).</p>
<p>You can use CSS’s <code>prefers-reduced-motion</code> media query to reduce or disable animations for users.</p>
<p>Personally, instead of disabling animations completely, I replace complex, distracting animations with more subtle ones to maintain functionality while respecting user preferences.</p>
<p>Here's how to use <code>prefers-reduced-motion</code> to create a simpler animation:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Default animation */</span>
<span class="hljs-keyword">@keyframes</span> complexAnimation {
    0% { <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(<span class="hljs-number">0</span>); <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>; }
    50% { <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(<span class="hljs-number">100px</span>); <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0.5</span>; }
    100% { <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(<span class="hljs-number">0</span>); <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>; }
}

<span class="hljs-selector-class">.element</span> {
    <span class="hljs-attribute">animation</span>: complexAnimation <span class="hljs-number">2s</span> ease-in-out;
}

<span class="hljs-comment">/* Simpler animation for reduced motion preference */</span>
<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">prefers-reduced-motion:</span> reduce) {
    <span class="hljs-keyword">@keyframes</span> simpleAnimation {
        0% { <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>; }
        100% { <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>; }
    }

    <span class="hljs-selector-class">.element</span> {
        <span class="hljs-attribute">animation</span>: simpleAnimation <span class="hljs-number">1s</span> ease-in-out;
    }
}
</code></pre>
<p>Here’s an example from the code above. If you have reduced motion enabled you’ll see a fading ball instead of a moving ball:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/leezee/embed/preview/PorrrQW?default-tab=result&amp;editable=true" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p><strong>Note</strong>: If you want to see the reduced motion in action, you can enable it in the <a target="_blank" href="https://developer.chrome.com/docs/devtools/rendering">rendering tab on Google Chrome</a>.</p>
<h2 id="heading-focus-within-for-nested-elements">Focus Within for Nested Elements</h2>
<p>You can highlight or style a parent element when any of its child elements receive focus to make it clear which group (like form inputs or dropdown menus) is currently being interacted with.</p>
<p>To do this, you can use CSS’s <code>:focus-within</code> pseudo-class which is used to style an element when any of its descendants receive focus either through keyboard navigation or user interaction.</p>
<p>For example, to highlight a fieldset when any item in the group is focused in a grouped control, you can do this:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
 <span class="hljs-selector-tag">fieldset</span> {
   <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
   <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ccc</span>;
 }

 <span class="hljs-selector-tag">fieldset</span><span class="hljs-selector-pseudo">:focus-within</span> {
   <span class="hljs-attribute">border-color</span>: <span class="hljs-number">#007BFF</span>; <span class="hljs-comment">/* highlight the fieldset when a user focuses on any input */</span>
 }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">fieldset</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">legend</span>&gt;</span>Choose a color:<span class="hljs-tag">&lt;/<span class="hljs-name">legend</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"radio"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"color"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"red"</span>&gt;</span> Red<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"radio"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"color"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"green"</span>&gt;</span> Green<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"radio"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"color"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"blue"</span>&gt;</span> Blue<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">fieldset</span>&gt;</span>
</code></pre>
<h2 id="heading-customize-contrast-options">Customize Contrast Options</h2>
<p>Sometimes you may be working on a design that uses lots of colors and might not maintain high contrast between text and background to fit an aesthetic. Or perhaps you're working on a design with lots of bright colors. In these cases, you should consider how your application renders for different users.</p>
<p>Some users with low vision or certain types of color blindness might need high contrast mode to differentiate text from the background more clearly. Other users sensitive to bright colors might prefer a softer, less jarring visual experience.</p>
<p>Some of these users might have their systems set to high or low contrast to help improve their experience. To customize their experience, you can use the CSS <code>prefers-contrast</code> media query.</p>
<p>The <code>prefers-contrast</code> media query allows you to tailor the contrast of your website or application based on the user's system settings.</p>
<p>Here's an example of using <code>prefers-contrast</code>:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* default styling preference */</span>
<span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">background-color</span>: white;
    <span class="hljs-attribute">color</span>: black;
}

<span class="hljs-comment">/* high contrast preference */</span>
<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">prefers-contrast:</span> more) {
    <span class="hljs-selector-tag">body</span> {
        <span class="hljs-attribute">background-color</span>: black;
        <span class="hljs-attribute">color</span>: white;
    }
    <span class="hljs-selector-tag">a</span> {
        <span class="hljs-attribute">color</span>: yellow;
    }
}
<span class="hljs-comment">/* low contrast preference */</span>

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">prefers-contrast:</span> less) {
    <span class="hljs-selector-tag">body</span> {
        <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f0f0f0</span>;
        <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>;
    }
    <span class="hljs-selector-tag">a</span> {
        <span class="hljs-attribute">color</span>: <span class="hljs-number">#555</span>;
    }
}
</code></pre>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/leezee/embed/preview/dyBBxgV?default-tab=result&amp;editable=true" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>In the example above, the <code>prefers-contrast: more</code> option ensures that when a user prefers high contrast, the background is black and the text is white, with yellow links for better visibility.</p>
<p>The <code>prefers-contrast: less</code> adjusts the color scheme to a softer color for users who prefer less contrast. The default style is used if the user has no specific contrast preference or if their preference is not detected.</p>
<p><strong>Note</strong>: If your design uses minimal colors and maintains high contrast between text and background or you're working with a design where text is minimal and the focus is on visual content (like image galleries or video players), you might not need <code>prefers-contrast</code> as much. But it's still good practice to consider contrasts.</p>
<h2 id="heading-enable-dark-mode">Enable Dark Mode</h2>
<p>You can use CSS to accommodate users’ preferences for dark or light modes. You can achieve this through the CSS <code>prefers-color-scheme</code> media query. The browser can detect the user's color preference and apply the style if provided in CSS.</p>
<p>Here's an example of how you can add a dark mode style to your site using CSS variables:</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">--background-color</span>: <span class="hljs-number">#ffffff</span>;
  <span class="hljs-attribute">--text-color</span>: <span class="hljs-number">#000000</span>;
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">prefers-color-scheme:</span> dark) {
  <span class="hljs-selector-pseudo">:root</span> {
    <span class="hljs-attribute">--background-color</span>: <span class="hljs-number">#000000</span>;
    <span class="hljs-attribute">--text-color</span>: <span class="hljs-number">#ffffff</span>;
  }
}

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--background-color);
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--text-color);
}
</code></pre>
<p>In the example above, the variables get updated if the browser detects a dark color scheme preference.</p>
<p>If you want to allow users to toggle between modes manually, you can use JavaScript for this:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
 <span class="hljs-comment">/* Default light mode styles */</span>
  <span class="hljs-selector-tag">body</span> {
   <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#ffffff</span>;
   <span class="hljs-attribute">color</span>: <span class="hljs-number">#000000</span>;
  }
 <span class="hljs-comment">/* Dark mode styles */</span>
  <span class="hljs-selector-tag">body</span><span class="hljs-selector-class">.dark-mode</span> {
   <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#000000</span>;
   <span class="hljs-attribute">color</span>: <span class="hljs-number">#ffffff</span>;
  }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"toggle-theme"</span>&gt;</span>Toggle Theme<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">const</span> toggleButton = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'toggle-theme'</span>);
  toggleButton.addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function">() =&gt;</span> {
   <span class="hljs-built_in">document</span>.body.classList.toggle(<span class="hljs-string">'dark-mode'</span>);
  });
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h2 id="heading-use-rem-units-for-responsive-typography">Use <code>rem</code> Units for Responsive Typography</h2>
<p>Using <code>rem</code> units for responsive typography can help enhance accessibility to adapt more dynamically to a user's preference. Since <code>rem</code> is relative to the root font size (typically set by the browser or user), it scales with changes in the base font size. This helps ensure that text remains readable without breaking layouts.</p>
<p>Users can set a preferred font size in their browser or operating system for better readability. When you use <code>rem</code>, the website content scales according to this setting which ensures that the text is not too small or too large for the users (which can happen when using fixed units like <code>px</code>).</p>
<p>When users zoom in using browser settings or increase their preferred text size, the <code>rem</code>-based text will scale appropriately.</p>
<p>The default root font size (usually 16px) is typically inherited from the browser, but you can set it explicitly if needed:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">html</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">100%</span>; <span class="hljs-comment">/* Default 16px */</span>
}
</code></pre>
<p>After setting the root font size, you can use <code>rem</code> unit for the rest of your content. For example:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2.5rem</span>; <span class="hljs-comment">/* Equivalent to 40px if root is 16px */</span>
}

<span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>; <span class="hljs-comment">/* Equivalent to 16px */</span>
}
</code></pre>
<h2 id="heading-use-animations-to-enhance-ux">Use Animations to Enhance UX</h2>
<p>CSS animations can enhance accessibility when used thoughtfully. They can help create an engaging and understandable experience for users.</p>
<p>Here are some ways that animations can help improve accessibility:</p>
<ul>
<li><p>You can use animations to indicate loading state to visually communicate to users that the system is working on a task.</p>
</li>
<li><p>Using animated text effects, like fades or scaling on headlines or important sections, can help guide users' eyes to important content. This can be useful for people with cognitive disabilities who benefit from clear visual hierarchies.</p>
</li>
<li><p>Subtle transitions for state change instead of having abrupt changes (like a modal popping up instantly) can create smoother transitions between different interface states.</p>
</li>
<li><p>Using animated highlights or shaking effects on form fields can provide visual feedback to users about input errors. You should pair these animations with labels or ARIA attributes to make it clear what the user needs to correct.</p>
</li>
<li><p>Animations can help users track focus, especially keyboard users or those with visual impairments. CSS transitions that highlight focused elements (for example by enlarging buttons or changing the border) assist users in understanding where they are within the page.</p>
</li>
</ul>
<h3 id="heading-best-practices">Best Practices:</h3>
<ul>
<li><p>Ensure animations are used purposefully, not just for aesthetic reasons.</p>
</li>
<li><p>Avoid overly long or continuous animations that can distract or annoy users.</p>
</li>
<li><p>Combine animations with other accessible features, such as screen reader announcements, to ensure all users understand content changes.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>When considering accessibility, well-structured HTML forms the foundation of an accessible page – but CSS also plays a vital role in enhancing that structure.</p>
<p>CSS alone cannot fix poorly structured HTML. But when it’s applied thoughtfully to a solid foundation, it ensures a more inclusive and engaging experience by improving visual hierarchy, readability, and interaction for users of all abilities.</p>
<p>Combining accessible HTML with CSS not only improves the user interface but also provides support for assistive technologies.</p>
<p>Thank you so much for reading this article. If you found it helpful, consider sharing. Happy coding!</p>
<p>You can connect with me on <a target="_blank" href="https://www.linkedin.com/in/elizabeth-meshioye/">LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use HTML Attributes to Make Your Websites and Apps More Accessible ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever used an attribute in HTML without fully understanding its purpose? You're not alone! Over time, I've dug into the meaning behind many HTML attributes, especially those that are crucial for accessibility. In this in-depth tutorial, I'll ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-html-attributes-to-make-your-websites-and-apps-more-accessible/</link>
                <guid isPermaLink="false">66db603bf7f8b7688af503af</guid>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ a11y ]]>
                    </category>
                
                    <category>
                        <![CDATA[ aria ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabeth Lola ]]>
                </dc:creator>
                <pubDate>Fri, 06 Sep 2024 20:04:11 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1725281991044/7edb0d70-c31e-4a41-bc24-232c75d0fae3.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever used an attribute in HTML without fully understanding its purpose? You're not alone! Over time, I've dug into the meaning behind many HTML attributes, especially those that are crucial for accessibility.</p>
<p>In this in-depth tutorial, I'll break down some key HTML attributes that enhance accessibility, explaining what they do, and when to use them effectively.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this tutorial, you should have a basic understanding of HTML and a little bit of Javascript knowledge as well.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-are-aria-attributes">What are ARIA Attributes?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-alt-attribute">The <code>alt</code> Attribute</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-aria-label-attribute">The <code>aria-label</code> Attribute</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-best-practices-for-using-aria-label">Best practices for Using <code>aria-label</code></a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-aria-labelledby-attribute">The <code>aria-labelledby</code> Attribute</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-is-aria-label-different-from-aria-labelledby">How is <code>aria-label</code> Different from <code>aria-labelledby</code>?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-best-practices-for-using-aria-labelledby">Best Practices for Using <code>aria-labelledby</code></a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-aria-describedby-attribute">The <code>aria-describedby</code> Attribute</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-best-practices-for-using-aria-describedby">Best Pracices for Using <code>aria-describedby</code></a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-role-attribute">The <code>role</code> Attribute</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-common-role-values">Common <code>role</code> Values</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-best-practices-for-using-the-role-attribute">Best Practices for Using the <code>role</code> Attribute</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-aria-controls-attribute">The <code>aria-controls</code> Attribute</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-best-practices-for-using-aria-controls">Best Practices for Using <code>aria-controls</code></a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-aria-selected-attribute">The <code>aria-selected</code> Attribute</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-best-practices-for-using-aria-selected">Best Practices for Using <code>aria-selected</code></a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-tabindex-attribute">The <code>tabindex</code> Attribute</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-possible-tabindex-values">Possible <code>tabindex</code> Values</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-best-practices-for-using-tabindex">Best Practices for Using <code>tabindex</code></a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-title-attribute">The <code>title</code> Attribute</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-accessibility-concerns-with-the-title-attribute">Accessibility Concerns with <code>title</code></a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-best-practices-for-using-the-title-attribute">Best Practices for Using the <code>title</code> Attribute</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-using-the-for-attribute-in-label">Using the <code>for</code> Attribute in <code>label</code></a></p>
<ul>
<li><a class="post-section-overview" href="#heading-best-practices-for-using-the-for-attribute">Best Practices for Using the <code>for</code> Attribute</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-scope-attribute">The <code>scope</code> Attribute</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-possible-scope-values">Possible <code>scope</code> Values</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-best-practices-for-using-the-scope-attribute">Best Practices for Using <code>scope</code></a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-aria-hidden-attribute">The <code>aria-hidden</code> Attribute</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-best-practices-for-using-aria-hidden">Best Practices for Using <code>aria-hidden</code></a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-inert-attribute">The <code>inert</code> Attribute</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-best-practices-for-using-the-inert-attribute">Best Practices for Using <code>inert</code></a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-aria-live-attribute">The <code>aria-live</code> Attribute</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-possible-values-for-aria-live">Possible Values for <code>aria-live</code></a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-best-practices-for-using-aria-live">Best Practices for Using <code>aria-live</code></a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-aria-roledescription-attribute">The <code>aria-roledescription</code> Attribute</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-best-practices-for-using-aria-roledescription">Best Practices for Using <code>aria-roledescription</code></a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-aria-atomic-attribute">The <code>aria-atomic</code> Attribute</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-the-aria-atomic-attribute">Best Practices for Using <code>aria-atomic</code></a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-what-are-aria-attributes">What Are ARIA Attributes?</h2>
<p>Most of the attributes listed in this article are ARIA attributes. ARIA, which stands for <strong>Accessible Rich Internet Applications</strong>, is a set of attributes defined by the W3C (World Wide Web Consortium) to enhance the accessibility of web applications.</p>
<p>ARIA attributes provide additional information to assistive technologies like screen readers. Using them correctly can make complex web applications more accessible to individuals with visual, auditory, or motor impairments.</p>
<p>One key principle of using ARIA is that sometimes it's best not to use it. Although this might seem contradictory, you should only ARIA attributes when necessary. Overusing ARIA can disrupt the experience for users relying on assistive technologies. While sighted users might not notice any issues, excessive or improper use of ARIA can negatively impact accessibility.</p>
<h2 id="heading-the-alt-attribute">The <code>alt</code> Attribute</h2>
<p>The <code>alt</code> attribute likely isn't new to you if you've used HTML images. You use it to provide <em>alternative</em> text that displays when an image isn't properly shown on the screen.</p>
<p>But the most important use of the <code>alt</code> attribute is for accessibility. If the <code>alt</code> attribute is not present in an image element, then a screen reader may announce the name of the image file or the URL of the image instead of explaining what it's showing. This can be unhelpful and we don't want that.</p>
<p>The content in the <code>alt</code> attribute should be concise because its primary purpose is to briefly describe an image for those who cannot see it. This includes users who rely on screen readers, search engines, and users with slow internet connections where images may not load. If the <code>alt</code> text is too long, it may include unnecessary details that don't add value to the user's understanding.</p>
<p>The <code>alt</code> attribute is different from an image caption. Captions are visible and can provide more context or additional information about an image. Using a caption as <code>alt</code> text can make it too long and redundant.</p>
<p>If the image is purely decorative, then the alt attribute should be left empty. If an image has an empty alt attribute, an assistive tool will skip it. This is important to help keep users focused on the content and not distract them with unnecessary information.</p>
<p>Here's an example of how you can use the alt attribute:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Lions are remarkable for their powerful roars, 
which can be heard up to five miles away. 
These roars are used to communicate with other 
members of the pride, as well as to ward off rival lions and intruders. 
Although lions are often associated with the African savannah, 
a small population of Asiatic lions still exists in India's Gir Forest, 
making them one of the world's most endangered big cats.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"lion.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"a lion"</span> /&gt;</span> <span class="hljs-comment">&lt;!-- brief and gives context to the paragraph --&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"background-stars.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span> <span class="hljs-comment">&lt;!-- This image is purely for 
decoration so it's left empty --&gt;</span>
</code></pre>
<h2 id="heading-the-aria-label-attribute">The <code>aria-label</code> Attribute</h2>
<p>The <code>aria-label</code> attribute is used to provide an accessible name to an element that might not have visible text. A common example of this is a button that contains an image or SVG.</p>
<p>A lot of elements have an accessible name – the accessible name is the content inside the element. The accessible name for the heading in this example is "Frequently Asked Questions"</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Frequently Asked Questions<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
</code></pre>
<p>Everyone, including people using assistive technology, would clearly understand the meaning of the example above because it contains visible content.</p>
<p>But in the example below, a user relying on a screen reader might miss the content in the button if it doesn't have an <code>aria-label</code>. This is because the content in the button is an SVG and the SVG does not contain any visible content:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Search"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
      <span class="hljs-attr">fill</span>=<span class="hljs-string">"#000000"</span> 
      <span class="hljs-attr">height</span>=<span class="hljs-string">"20px"</span>
      <span class="hljs-attr">width</span>=<span class="hljs-string">"20px"</span>
      <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span> 
      <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 488.4 488.4"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">g</span> <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"0"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">g</span> <span class="hljs-attr">stroke-linecap</span>=<span class="hljs-string">"round"</span> <span class="hljs-attr">stroke-linejoin</span>=<span class="hljs-string">"round"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">g</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">g</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">g</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M0,203.25c0,112.1,91.2,203.2,203.2,203.2c51.6,0,98.8-19.4,134.7-51.2l129.5,129.5c2.4,2.4,5.5,3.6,8.7,3.6 s6.3-1.2,8.7-3.6c4.8-4.8,4.8-12.5,0-17.3l-129.6-129.5c31.8-35.9,51.2-83,51.2-134.7c0-112.1-91.2-203.2-203.2-203.2 S0,91.15,0,203.25z M381.9,203.25c0,98.5-80.2,178.7-178.7,178.7s-178.7-80.2-178.7-178.7s80.2-178.7,178.7-178.7 S381.9,104.65,381.9,203.25z"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span> 
        <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>Do not overuse the <code>aria-label</code>. Not all content needs an <code>aria-label</code> – for example, if you have a button that contains an image with <code>alt</code>, or an SVG with a <code>title</code>, then those attributes act as the accessible name for that element.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"search-icon.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Search"</span> /&gt;</span> <span class="hljs-comment">&lt;!-- no need for aria-label --&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Another example --&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
    <span class="hljs-attr">fill</span>=<span class="hljs-string">"#000000"</span>
    <span class="hljs-attr">height</span>=<span class="hljs-string">"20px"</span>
    <span class="hljs-attr">width</span>=<span class="hljs-string">"20px"</span>
    <span class="hljs-attr">role</span>=<span class="hljs-string">"image"</span>
    <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
    <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 488.4 488.4"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Search Icon<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span> <span class="hljs-comment">&lt;!-- Accessible name --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">g</span> <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"0"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">g</span> <span class="hljs-attr">stroke-linecap</span>=<span class="hljs-string">"round"</span> <span class="hljs-attr">stroke-linejoin</span>=<span class="hljs-string">"round"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">g</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">g</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">g</span>&gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M0,203.25c0,112.1,91.2,203.2,203.2,203.2c51.6,0,98.8-19.4,134.7-51.2l129.5,129.5c2.4,2.4,5.5,3.6,8.7,3.6 s6.3-1.2,8.7-3.6c4.8-4.8,4.8-12.5,0-17.3l-129.6-129.5c31.8-35.9,51.2-83,51.2-134.7c0-112.1-91.2-203.2-203.2-203.2 S0,91.15,0,203.25z M381.9,203.25c0,98.5-80.2,178.7-178.7,178.7s-178.7-80.2-178.7-178.7s80.2-178.7,178.7-178.7 S381.9,104.65,381.9,203.25z"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span> 
        <span class="hljs-tag">&lt;<span class="hljs-name">g</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">g</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>You should use the <code>aria-label</code> sparingly and appropriately. Overusing the attribute can lead to several issues:</p>
<ul>
<li><p>The <code>aria-label</code> content is not visible to sighted users. If a user with a cognitive disability is using a screen reader for support, they might not understand why they’re hearing different information from what they see on the screen.</p>
</li>
<li><p>Using <code>aria-label</code> extensively across a large codebase can make the HTML harder to maintain. You may struggle to track where labels are coming from, especially if they’re set programmatically or in multiple places.</p>
</li>
</ul>
<h3 id="heading-best-practices-for-using-aria-label">Best Practices for Using <code>aria-label</code></h3>
<ul>
<li><p>Whenever possible, use visible text labels. They’re easier to understand and maintain, and they ensure consistent experiences for all users.</p>
</li>
<li><p>When Possible: If there is already a visible label on the page, use <code>aria-labelledby</code> to link the element to the existing text instead of creating a new label with <code>aria-label</code> (we'll talk about this below).</p>
</li>
<li><p>If you use <code>aria-label</code>, keep the text short and to the point. It should describe the element’s purpose in as few words as possible.</p>
</li>
</ul>
<h2 id="heading-the-aria-labelledby-attribute">The <code>aria-labelledby</code> Attribute</h2>
<p>The <code>aria-labelledby</code> attribute is used to associate an element with another element that serves as its label. It links the target element to one or more other elements on the page that contain the text that should be used as the label.</p>
<p>You can use this attribute when there is already a visible text label or when the label needs to be composed of multiple text elements.</p>
<p>For example, you can use <code>aria-labelledby</code> in a <code>&lt;section&gt;</code> element to associate it with a heading or other text that serves as a label for the entire section.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"about-heading"</span>&gt;</span>About Us<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span> 
<span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"about-heading"</span>&gt;</span> <span class="hljs-comment">&lt;!-- use the id of the h2 --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>We are a company dedicated to providing excellent service...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"services-heading"</span>&gt;</span>Our Services<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"services-heading"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>We offer a wide range of services including...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
</code></pre>
<p>Sometimes, you might want to combine multiple pieces of text as the label. You can do this by listing multiple IDs in the <code>aria-labelledby</code> attribute:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"dialog-title"</span>&gt;</span>Confirmation Required<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"dialog-description"</span>&gt;</span>Are you sure you want to delete this item?<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"dialog-title dialog-description"</span>&gt;</span>Yes<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>The <code>aria-labelledby</code> is similar to the <code>aria-label</code> in that its purpose is to provide an accessible element.</p>
<h3 id="heading-how-is-aria-label-different-from-aria-labelledby">How is <code>aria-label</code> Different from <code>aria-labelledby</code>?</h3>
<p><code>aria-label</code> directly assigns a string of text as a label for an element. This text is not visible on the screen but is announced by assistive technologies like screen readers. It’s typically used when there is no visible text label.</p>
<p><code>aria-labelledby</code> points to one or more existing elements on the page (using their <code>id</code> attributes) that should be used as the label for the element. The label text is visible to all users because it’s part of the content of another element.</p>
<h3 id="heading-best-practices-for-using-aria-labelledby">Best Practices for Using <code>aria-labelledby</code></h3>
<ul>
<li><p>Use <code>aria-labelledby</code> over <code>aria-label</code> when there is already text on the page that can serve as the label. This reduces redundancy and ensures that both sighted users and screen reader users see the same content.</p>
</li>
<li><p>The <code>id</code> attributes referenced by <code>aria-labelledby</code> must be unique on the page and correctly point to existing elements. If the ID is missing or incorrect, the label won’t work, leading to accessibility issues.</p>
</li>
<li><p>When combining multiple labels, ensure that the resulting label makes sense when read together. The order of IDs in <code>aria-labelledby</code> matters, as screen readers will read the labels in the order they are listed.</p>
</li>
<li><p>Like <code>aria-label</code>, avoid overusing <code>aria-labelledby</code> in situations where a simpler approach (like using a visible <code>label</code> element directly) would suffice. This helps keep the code maintainable and reduces the cognitive load for users.</p>
</li>
</ul>
<h2 id="heading-the-aria-describedby-attribute">The <code>aria-describedby</code> Attribute</h2>
<p>The <code>aria-describedby</code> attribute is used to associate an element with one or more elements that provide additional descriptive information about it. The <code>aria-describedby</code> attribute is used to provide additional context or instructions to an element.</p>
<p>Unlike <code>aria-labelledby</code>, which is meant to provide a label or name, <code>aria-describedby</code> is intended to give users more detailed information or context about an element, often to supplement what they already know from the label.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"full-name"</span>&gt;</span>Full name<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"full-name"</span> <span class="hljs-attr">aria-describedby</span>=<span class="hljs-string">"info"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"info"</span>&gt;</span>Enter your full name.<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
</code></pre>
<p>When both <code>aria-labelledby</code> and <code>aria-describedby</code> are used on the same element, screen readers will first announce the label (from <code>aria-labelledby</code>), then the role of the element (for example, "button"), and finally the description (from <code>aria-describedby</code>).</p>
<h3 id="heading-best-practices-for-using-aria-describedby">Best Practices for Using <code>aria-describedby</code></h3>
<ul>
<li><p>Apply <code>aria-describedby</code> when you need to provide users with additional context or instructions that go beyond the label. This is particularly useful for forms, complex controls, or any element that might require clarification.</p>
</li>
<li><p>While <code>aria-describedby</code> is meant for more detailed descriptions, avoid overly long text. Keep the description focused on what the user needs to know to interact with the element effectively.</p>
</li>
<li><p>Just like with <code>aria-labelledby</code>, ensure that the elements referenced by <code>aria-describedby</code> have unique and relevant <code>id</code> attributes. The content of these elements should be directly relevant to the element they describe.</p>
</li>
</ul>
<h2 id="heading-the-role-attribute">The <code>role</code> Attribute</h2>
<p>The role attribute is used to specify the role of an element. You can use it to override the default role of a semantic element. It helps assistive technologies understand how an element should be interpreted or interacted with.</p>
<p>When using non-semantic elements (like <code>&lt;div&gt;</code> or <code>&lt;span&gt;</code>) to create interactive controls (buttons, dialogs, tabs, and so on), the <code>role</code> attribute informs assistive technologies of the element’s intended behavior. You can also use the role to define landmark roles that assist in navigation, such as <code>banner</code> or <code>complementary</code>, which defines the structure of the page for screen reader users.</p>
<h3 id="heading-common-role-values">Common <code>role</code> Values</h3>
<p>Roles for Landmark Regions:</p>
<ul>
<li><p><code>banner</code>: Represents the site header.</p>
</li>
<li><p><code>navigation</code>: Defines a navigation section of the page, often for site or page navigation links.</p>
</li>
<li><p><code>main</code>: Marks the main content of a document, distinct from sidebars, footers, and so on.</p>
</li>
<li><p><code>contentinfo</code>: Represents the footer information.</p>
</li>
</ul>
<p>This example below is just for demonstration purposes – you should use the right semantic element when possible:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"banner"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My Website<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"navigation"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#home"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#about"</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"main"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Welcome to My Website<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Here is some main content...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"contentinfo"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-symbol">&amp;copy;</span> 2024 My Website<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Roles for Widgets and Interactive Elements:</p>
<ul>
<li><p><code>button</code>: Represents a button element, which users can click to trigger an action.</p>
</li>
<li><p><code>dialog</code>: Marks a dialog box or modal that requires user interaction.</p>
</li>
<li><p><code>alert</code>: Identifies an element as an important message or alert that requires user attention.</p>
</li>
<li><p><code>tablist</code>, <code>tab</code>, <code>tabpanel</code>: Used for tabbed interfaces, where <code>tablist</code> contains the tabs, and each <code>tab</code> controls the visibility of its corresponding <code>tabpanel</code>.</p>
</li>
</ul>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">tabindex</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"submitForm()"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"dialog"</span> <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"dialog-title"</span> <span class="hljs-attr">aria-modal</span>=<span class="hljs-string">"true"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"dialog-title"</span>&gt;</span>Confirmation<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Are you sure you want to proceed?<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"closeDialog()"</span>&gt;</span>Close<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Example of Tabbed panel:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tablist"</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Sample Tabs"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tab"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tab-1"</span> <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"panel-1"</span> <span class="hljs-attr">aria-selected</span>=<span class="hljs-string">"true"</span> <span class="hljs-attr">tabindex</span>=<span class="hljs-string">"0"</span>&gt;</span>Tab 1<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tab"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tab-2"</span> <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"panel-2"</span> <span class="hljs-attr">aria-selected</span>=<span class="hljs-string">"false"</span> <span class="hljs-attr">tabindex</span>=<span class="hljs-string">"-1"</span>&gt;</span>Tab 2<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tab"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tab-3"</span> <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"panel-3"</span> <span class="hljs-attr">aria-selected</span>=<span class="hljs-string">"false"</span> <span class="hljs-attr">tabindex</span>=<span class="hljs-string">"-1"</span>&gt;</span>Tab 3<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tabpanel"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"panel-1"</span> <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"tab-1"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Content for Tab 1<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is the content of the first tab.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tabpanel"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"panel-2"</span> <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"tab-2"</span> <span class="hljs-attr">hidden</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Content for Tab 2<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is the content of the second tab.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tabpanel"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"panel-3"</span> <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"tab-3"</span> <span class="hljs-attr">hidden</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Content for Tab 3<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is the content of the third tab.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h3 id="heading-best-practices-for-using-the-role-attribute">Best Practices for Using the <code>role</code> Attribute</h3>
<ul>
<li><p>Always prefer using native HTML elements that already have the appropriate role (for example, <code>&lt;button&gt;</code>, <code>&lt;header&gt;</code>, <code>&lt;nav&gt;</code>, <code>&lt;main&gt;</code>). This provides better accessibility support across a wider range of browsers and devices.</p>
</li>
<li><p>Don't <strong>overuse</strong> or <strong>misuse</strong> the <code>role</code> attribute as this can lead to confusion and reduced accessibility. Use <code>role</code> to enhance or clarify when needed, not to replace semantic HTML.</p>
</li>
<li><p>Understand implicit roles. Many HTML elements have implicit roles. For example, an <code>&lt;a&gt;</code> element with an <code>href</code> attribute automatically has the <code>link</code> role. Avoid adding redundant <code>role</code> attributes to these elements.</p>
</li>
</ul>
<h2 id="heading-the-aria-controls-attribute">The <code>aria-controls</code> Attribute</h2>
<p>The <code>aria-controls</code> attribute informs a screen reader that the element is controlled or affected by another element. It's commonly used to indicate that a component (like a button or a tab) controls or interacts with another part of the page (like a panel or a menu). It is also used in interactive components such as tabs, accordions, and sliders to describe which parts of the page are affected when the user interacts with the component.</p>
<p>For example, you can use <code>aria-controls</code> on a tab button to indicate which panel each button controls:</p>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!-- Tab Buttons --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tab1"</span> <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"panel1"</span>&gt;</span>Tab 1<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tab2"</span> <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"panel2"</span>&gt;</span>Tab 2<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Content Panels --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"panel1"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tabpanel"</span>&gt;</span>Content for Tab 1<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"panel2"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"tabpanel"</span>&gt;</span>Content for Tab 2<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h3 id="heading-best-practices-for-using-aria-controls">Best Practices for Using <code>aria-controls</code></h3>
<ul>
<li><p>Ensure that the ID used in <code>aria-controls</code> matches the <code>id</code> of the controlled element exactly.</p>
</li>
<li><p>Use <code>aria-controls</code> in conjunction with role and state attributes like <code>aria-selected</code>, or <code>role="tabpanel"</code> to provide more complete information about the controlled elements and their states.</p>
</li>
<li><p>Apply <code>aria-controls</code> to interactive elements such as buttons or links that have a direct effect on other elements. It is not typically used for non-interactive content.</p>
</li>
</ul>
<h2 id="heading-the-aria-selected-attribute">The <code>aria-selected</code> Attribute</h2>
<p>The <code>aria-selected</code> attribute is used to indicate the current selection state of an element within a group of selectable items. A selectable item could be an option in a menu, a tab in a tabbed panel, or an item in a list box.</p>
<p>Here's an example of the selection state in a list box. <code>aria-selected="true"</code> in option 1 indicates that Option 1 is currently selected.</p>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!-- Listbox --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"listbox"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"option"</span> <span class="hljs-attr">aria-selected</span>=<span class="hljs-string">"true"</span>&gt;</span>Option 1<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"option"</span> <span class="hljs-attr">aria-selected</span>=<span class="hljs-string">"false"</span>&gt;</span>Option 2<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"option"</span> <span class="hljs-attr">aria-selected</span>=<span class="hljs-string">"false"</span>&gt;</span>Option 3<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
</code></pre>
<h3 id="heading-best-practices-for-using-aria-selected">Best Practices for Using <code>aria-selected</code></h3>
<ul>
<li><p>Use <code>aria-selected="true"</code> for the selected item and <code>aria-selected="false"</code> for non-selected items. The value should be a string, not a boolean.</p>
</li>
<li><p>Ensure that the visual state of the element (for example, active tab or selected option) matches the <code>aria-selected</code> value. Inconsistent states can lead to confusion for users of assistive technologies.</p>
</li>
<li><p>Use <code>aria-selected</code> in conjunction with appropriate <code>role</code> attributes (for example, <code>role="option"</code> for listbox items) to provide complete context.</p>
</li>
<li><p>Ensure that <code>aria-selected</code> is updated dynamically as users interact with the interface. For example, when a user selects a new option, update the <code>aria-selected</code> attribute accordingly.</p>
</li>
</ul>
<h2 id="heading-the-tabindex-attribute">The <code>tabindex</code> Attribute</h2>
<p>The <code>tabindex</code> attribute is used to control the keyboard navigation of an element. You can use it to activate focus for non-interactive elements like <code>div</code>, <code>p</code>, or <code>span</code> or disable focus for interactive elements like <code>button</code>, <code>a</code>, <code>input</code>. You can also use it to control focus order on a page.</p>
<h3 id="heading-possible-tabindex-values">Possible <code>tabindex</code> Values</h3>
<p><strong>Positive values:</strong> Elements with positive values become focusable and are included in the tab order with their numbers determining the order in which they are focused. Elements with lower numbers are focused before elements with higher numbers.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">tabindex</span>=<span class="hljs-string">"2"</span>&gt;</span>Cancel<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span> <span class="hljs-comment">&lt;!-- This will recieve focus last --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">tabindex</span>=<span class="hljs-string">"1"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span> <span class="hljs-comment">&lt;!-- This will recieve focus first --&gt;</span>
</code></pre>
<p>Elements with the same values will be navigated in the order in which they appear.</p>
<p><strong>Note:</strong> Using positive <code>tabindex</code> values can lead to a confusing and non-intuitive tab order. It is generally better to use <code>tabindex="0"</code> for elements that should be part of the natural tab order.</p>
<p><strong>Zero:</strong> You use this to make an element focusable and include it in the natural tab order based on its position in the document. It's useful for making elements focusable that are not normally focusable (like <code>&lt;div&gt;</code> or <code>&lt;span&gt;</code>).</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">tabindex</span>=<span class="hljs-string">"0"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> 
<span class="hljs-comment">&lt;!-- The element becomes focusable using the keyboard --&gt;</span>
</code></pre>
<p><strong>Negative values:</strong> You use this to remove an element from the tab order, meaning it cannot be focused using the <code>Tab</code> key. But it can still be focused programmatically (via JavaScript). It's useful for elements that should not be focusable by default but may need to be focusable under certain conditions.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"other-names"</span> <span class="hljs-attr">tabindex</span>=<span class="hljs-string">"-1"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"email"</span>&gt;</span>

<span class="hljs-comment">&lt;!-- other-names will be skipped when tabbing through the inputs; 
only name and email will receive focus --&gt;</span>
</code></pre>
<h3 id="heading-best-practices-for-using-tabindex">Best Practices for Using <code>tabindex</code></h3>
<ul>
<li><p>Rely on the natural tab order as much as possible. Use <code>tabindex="0"</code> to include elements in the tab order and avoid using positive values unless absolutely necessary.</p>
</li>
<li><p>Using positive <code>tabindex</code> values can create an unpredictable tab order and make it harder for users to navigate. It's better to use the default flow and <code>tabindex="0"</code>.</p>
</li>
<li><p>Use <code>tabindex="-1"</code> for elements not intended to be focused.</p>
</li>
<li><p>Ensure that the focus order follows a logical and intuitive sequence, which matches the visual layout and interaction flow of the page.</p>
</li>
<li><p>Test with keyboard and assistive technologies.</p>
</li>
<li><p>When dynamically adding or removing focusable elements (for example, through JavaScript), ensure that focus management is handled properly to maintain a smooth experience.</p>
</li>
</ul>
<h2 id="heading-the-title-attribute">The <code>title</code> Attribute</h2>
<p>The <code>title</code> attribute in HTML is used to provide additional information about an element. The content in the attribute shows in a tooltip when a user hovers over the element containing the title. It can be applied to most HTML elements, including links, images, and form fields.</p>
<p>You can use the title attribute to provide a brief explanation or description of the content of an element. For example, you can use it to clarify the meaning of abbreviations or acronyms when used with the <code>&lt;abbr&gt;</code> tag.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">abbr</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"World Wide Web"</span>&gt;</span>WWW<span class="hljs-tag">&lt;/<span class="hljs-name">abbr</span>&gt;</span>
<span class="hljs-comment">&lt;!-- Hovering over "WWW" displays the tooltip "World Wide Web," 
explaining the abbreviation. --&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"logo.png"</span> 
<span class="hljs-attr">alt</span>=<span class="hljs-string">"Company Logo"</span> 
<span class="hljs-attr">title</span>=<span class="hljs-string">"This is the logo of our company"</span>&gt;</span>
<span class="hljs-comment">&lt;!-- Users will see "This is the logo of our company" 
when hovering over the image. --&gt;</span>
</code></pre>
<h3 id="heading-accessibility-concerns-with-the-title-attribute">Accessibility Concerns with the <code>title</code> Attribute</h3>
<p>The title attribute can be useful, but it comes with some accessibility concerns:</p>
<ul>
<li><p>Screen readers do not consistently announce the <code>title</code> attribute, especially when there is also an <code>alt</code> attribute – or they may ignore it altogether. Users of assistive technologies may miss out on the information provided by the <code>title</code> attribute, especially if they rely solely on screen readers.</p>
</li>
<li><p>The tooltip generated by the <code>title</code> attribute typically appears only on hover with a mouse or trackpad. Users who navigate with a keyboard or touch screen may not have access to this information.</p>
</li>
<li><p>The content of the <code>title</code> attribute is hidden by default and only revealed on hover. This makes it less accessible to users who don't know they need to hover to get additional information.</p>
</li>
<li><p>Tooltips can be difficult to read because they often disappear quickly, and their content might be truncated or too long to fit within the tooltip window.</p>
</li>
</ul>
<h3 id="heading-best-practices-for-using-the-title-attribute">Best Practices for Using the <code>title</code> Attribute</h3>
<ul>
<li><p>Avoid relying solely on the <code>title</code> attribute. Ensure that critical information is available in a more accessible manner, such as visible text or ARIA attributes.</p>
</li>
<li><p>Use the <code>title</code> attribute for supplementary, non-essential information that enhances user experience but isn’t critical to understanding the content.</p>
</li>
<li><p>For form inputs, use the <code>aria-describedby</code> attribute to associate additional instructions with a form element. Use visible labels or descriptions instead of or in addition to the <code>title</code> attribute to ensure that all users have access to the information.</p>
</li>
<li><p>If you use the <code>title</code> attribute, keep the text brief and to the point. Long tooltips can be difficult to read and may get truncated.</p>
</li>
</ul>
<h2 id="heading-using-the-for-attribute-in-label">Using the <code>for</code> Attribute in <code>label</code></h2>
<p>The <code>for</code> attribute, when used in <code>&lt;label&gt;</code>, is used to connect a label to its corresponding form control element – that is <code>&lt;input&gt;</code>, <code>&lt;select&gt;</code>, or <code>&lt;textarea&gt;</code>. Screen readers will announce the label when the assigned input is focused. When used correctly, clicking on the label will focus on the corresponding input.</p>
<p>The value of the <code>for</code> attribute should match the <code>id</code> of the input it is associated with:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"fullname"</span>&gt;</span>Full Name<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"fullname"</span>&gt;</span>
<span class="hljs-comment">&lt;!-- When the user clicks on the "Full Name" label, 
the cursor will focus on the corresponding input field. --&gt;</span>
</code></pre>
<h3 id="heading-best-practices-for-using-the-for-attribute">Best Practices for Using the <code>for</code> Attribute</h3>
<ul>
<li><p>Ensure that each form control has a unique <code>id</code> attribute so that the <code>for</code> attribute can correctly reference it. Avoid using duplicate <code>id</code> values on the same page.</p>
</li>
<li><p>Avoid empty <code>for</code> attributes. If there’s no associated form control, it can confuse users of assistive technologies.</p>
</li>
<li><p>Position labels close to their associated form controls. Typically, labels should be placed above or to the left of the form controls for optimal readability and usability.</p>
</li>
</ul>
<h2 id="heading-the-scope-attribute">The <code>scope</code> Attribute</h2>
<p>The <code>scope</code> attribute is used in HTML tables to define the relationship between table headers and the cells they describe. The attribute is particularly important for accessibility because it helps screen readers and other assistive technologies understand the structure of the table and convey the correct information to users.</p>
<p>The <code>scope</code> attribute is applied to <code>&lt;th&gt;</code> (table header) elements to specify whether the header applies to a row, a column, or a group of rows or columns</p>
<h3 id="heading-possible-scope-values">Possible <code>scope</code> Values</h3>
<ul>
<li><code>row</code>: Indicates that the <code>&lt;th&gt;</code> element is a header for a row. In the example below, <code>scope="row"</code> is used for the first <code>&lt;th&gt;</code> element in each row, indicating that the header applies to the entire row.</li>
</ul>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">table</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"row"</span>&gt;</span>Product A<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$1000<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$1200<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$1100<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"row"</span>&gt;</span>Product B<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$900<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$950<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$1000<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
</code></pre>
<ul>
<li><code>col</code>: Indicates that the <code>&lt;th&gt;</code> element is a header for a column.</li>
</ul>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">table</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Age<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Occupation<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
<span class="hljs-comment">&lt;!-- The scope="col" attribute indicates that each &lt;th&gt; element 
serves as a header for the corresponding column beneath it. --&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Jane<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>30<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Engineer<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Tobe<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>25<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Designer<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
</code></pre>
<ul>
<li><code>rowgroup</code>: Indicates that the <code>&lt;th&gt;</code> element is a header for a group of rows. In the example below, the rows "Marketing Department" and "Sales Department" have the <code>scope="rowgroup"</code> attribute to indicate that these rows act as headers for the groups of rows that follow:</li>
</ul>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">table</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Department<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Employee Name<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Position<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Salary<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Row Group for the Marketing Department --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"rowgroup"</span> <span class="hljs-attr">colspan</span>=<span class="hljs-string">"4"</span>&gt;</span>Marketing Department<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"row"</span>&gt;</span>Amari Pere<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Marketing Manager<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$75,000<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"row"</span>&gt;</span>Uyati Hope<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>SEO Specialist<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$65,000<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Row Group for the Sales Department --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"rowgroup"</span> <span class="hljs-attr">colspan</span>=<span class="hljs-string">"4"</span>&gt;</span>Sales Department<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"row"</span>&gt;</span>Timini Prosper<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Sales Manager<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$80,000<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"row"</span>&gt;</span>Delilu Pink<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Account Executive<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$70,000<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
</code></pre>
<ul>
<li><code>colgroup</code>: Indicates that the <code>&lt;th&gt;</code> element is a header for a group of columns. In the example below, <code>scope="colgroup"</code> is used to indicate that the first row of headers applies to groups of columns (Q1 and Q2), while <code>scope="col"</code> and <code>scope="row"</code> are used for individual columns and rows.</li>
</ul>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">table</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"colgroup"</span>&gt;</span>Region<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"colgroup"</span>&gt;</span>Q1<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"colgroup"</span>&gt;</span>Q2<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Sales<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Profit<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Sales<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Profit<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"row"</span>&gt;</span>North<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$2000<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$400<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$2500<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$500<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"row"</span>&gt;</span>South<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$1500<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$300<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$1800<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>$350<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
</code></pre>
<h3 id="heading-best-practices-for-using-the-scope-attribute">Best Practices for Using the <code>scope</code> Attribute</h3>
<ul>
<li><p>Always define <code>scope</code> for complex tables to clarify the relationship between headers and data cells.</p>
</li>
<li><p>Simplify table structures when possible. While the <code>scope</code> attribute helps with accessibility, consider simplifying table structures where possible. If a table is too complex, it might be difficult for all users to understand, even with proper markup.</p>
</li>
<li><p>For particularly complex tables, consider using ARIA attributes like <code>aria-labelledby</code> or <code>aria-describedby</code> to provide additional context and ensure that all users can navigate the table effectively.</p>
</li>
<li><p>After applying the <code>scope</code> attribute, test the table with screen readers to ensure that the relationships between headers and data cells are announced correctly.</p>
</li>
<li><p>Don’t use <code>scope</code> in situations where it’s unnecessary. For simple tables where each header is clearly associated with a single row or column, HTML’s default behavior is usually sufficient.</p>
</li>
</ul>
<h2 id="heading-the-aria-hidden-attribute">The <code>aria-hidden</code> Attribute</h2>
<p>The aria-hidden attribute is used to control the visibility of an element for assistive technologies while it's still visible on the screen. You can use it to hide purely decorative elements, like icons or images, that don't add meaningful information to the content. This helps prevent screen readers from reading unnecessary information.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span>🔍<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    Search
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>You can also use it to hide content that has already been announced to prevent redundancy in what screen readers announce. For content that is toggled on and off (like modals, or expandable sections), you can use <code>aria-hidden</code> to hide the inactive content from screen readers, ensuring that they only interact with the visible, active content.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span>✉<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span> <span class="hljs-comment">&lt;!-- hide decorative icon --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Messages<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>You can also use <code>aria-hidden</code> when creating complex widgets (like carousels or tabbed interfaces) to hide inactive panels or slides from assistive technologies, focusing their attention on the active part of the widget.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"menu"</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Menu content here --&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"toggleMenu()"</span>&gt;</span>Toggle Menu<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">const</span> toggleMenu = <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> menu = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'menu'</span>);
        <span class="hljs-keyword">const</span> isHidden = menu.getAttribute(<span class="hljs-string">'aria-hidden'</span>) === <span class="hljs-string">'true'</span>;

        menu.setAttribute(<span class="hljs-string">'aria-hidden'</span>, !isHidden);
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h3 id="heading-best-practices-for-using-aria-hidden">Best Practices for Using <code>aria-hidden</code></h3>
<ul>
<li><p>Only use <code>aria-hidden</code> when you need to hide content from screen readers to avoid overwhelming users with redundant or irrelevant information.</p>
</li>
<li><p>Do not use on elements that users need to interact with, like buttons or links.</p>
</li>
<li><p>Ensure that <code>aria-hidden</code> accurately reflects the visibility of elements on the screen. If an element becomes visible or hidden via JavaScript or CSS, update <code>aria-hidden</code> accordingly to maintain accessibility.</p>
</li>
<li><p>In a team environment, document why and where <code>aria-hidden</code> is used in your codebase, so that other team members understand its purpose and can maintain it properly.</p>
</li>
</ul>
<h2 id="heading-the-inert-attribute">The <code>inert</code> Attribute</h2>
<p>The <code>inert</code> attribute prevents an element and all of its descendants from being focusable, interactive, or perceivable by assistive technologies. When an element has the <code>inert</code> attribute, it cannot receive focus, be clicked on, or be interacted with in any way. It's also hidden from assistive technologies like screen readers.</p>
<p>Unlike <code>aria-hidden</code>, which only affects accessibility, <code>inert</code> applies to all user interactions. The inert attribute can be used to disable sections of a page that are temporarily irrelevant, such as during form validation errors, while loading data, or when a certain section is hidden but still in the DOM. It can also be used in complex user interfaces like multi-step forms or wizards to ensure that users only interact with the current step or section</p>
<p>The most common use of inert, however, is in a modal, where you want to prevent users from interacting with the background content while the modal is open.</p>
<p>Like in the example below, when the modal is open the <code>inert</code> attribute is added to the main content, making it non-interactive and hidden from screen readers. When the modal is closed, the <code>inert</code> attribute is removed, and the main content becomes interactive again.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"main-content"</span> <span class="hljs-attr">inert</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is the main content of the page. It will be inactive when the modal is open.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"modal"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"dialog"</span> <span class="hljs-attr">aria-modal</span>=<span class="hljs-string">"true"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Modal Title<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is the content inside the modal.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"closeModal()"</span>&gt;</span>Close Modal<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">openModal</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'main-content'</span>).setAttribute(<span class="hljs-string">'inert'</span>, <span class="hljs-string">''</span>);
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'modal'</span>).style.display = <span class="hljs-string">'block'</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">closeModal</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'main-content'</span>).removeAttribute(<span class="hljs-string">'inert'</span>);
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'modal'</span>).style.display = <span class="hljs-string">'none'</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h3 id="heading-best-practices-for-using-the-inert-attribute">Best Practices for Using the <code>inert</code> Attribute</h3>
<ul>
<li><p>Ensure that when you use <code>inert</code>, the visually inactive or disabled state of elements is clear to sighted users. For example, dimming or blurring background content when a modal is open can complement the <code>inert</code> attribute.</p>
</li>
<li><p>Don't overuse <code>inert</code>, as doing so might unintentionally make significant portions of your page non-interactive and inaccessible. Use it judiciously to manage user focus and interaction only when necessary.</p>
</li>
<li><p>When dynamically adding and removing the <code>inert</code> attribute, ensure that it is properly removed when no longer needed so that users can regain access to previously disabled content.</p>
</li>
</ul>
<h2 id="heading-the-aria-live-attribute">The <code>aria-live</code> Attribute</h2>
<p>You can use the <code>aria-live</code> attribute to notify assistive technologies about dynamic content changes on a webpage. When <code>aria-live</code> is applied to an element, screen readers are alerted when the content inside that element is updated, ensuring that users are informed about important changes that occur after the page has initially loaded.</p>
<p>This attribute can be useful for content that updates dynamically, such as notifications, alerts, chat messages, or stock prices. It ensures that users are aware of changes that might otherwise go unnoticed.</p>
<h3 id="heading-possible-values-for-aria-live">Possible Values for <code>aria-live</code></h3>
<p>There are three main values: <code>off</code>, <code>polite</code>, and <code>assertive</code>.</p>
<ul>
<li><p><code>off</code>: Default value, updates to the element will not be announced by screen readers.</p>
</li>
<li><p><code>polite</code>: Updates will be announced by the screen reader, but only after the user has finished interacting with the current task or reading other content. This ensures that the update does not interrupt the user’s current activity.</p>
</li>
</ul>
<p>In the example below, each new message is added to the <code>#messages</code> container, which has <code>aria-live="polite"</code>. The screen reader will announce the new message only after the user finishes their current activity.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"chat-window"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"messages"</span> <span class="hljs-attr">aria-live</span>=<span class="hljs-string">"polite"</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- Existing messages are here --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>John: Hello!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>You: Hi there!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"addMessage()"</span>&gt;</span>Send Message<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addMessage</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> newMessage = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'div'</span>);
    newMessage.textContent = <span class="hljs-string">'Alice: How are you?'</span>;
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'messages'</span>).appendChild(newMessage);
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<ul>
<li><code>assertive</code>: Updates will be announced immediately, interrupting whatever the screen reader is currently announcing. Use this for urgent or critical information that requires the user’s immediate attention.</li>
</ul>
<p>In the example below, updates to the stock prices are placed within a container that has <code>aria-live="assertive"</code>.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"stock-ticker"</span> <span class="hljs-attr">aria-live</span>=<span class="hljs-string">"assertive"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Initial stock prices --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"stock1"</span>&gt;</span>Stock A: $100<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"stock2"</span>&gt;</span>Stock B: $150<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"updateStockPrices()"</span>&gt;</span>Update Prices<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateStockPrices</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'stock1'</span>).textContent = <span class="hljs-string">'Stock A: $95'</span>;
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'stock2'</span>).textContent = <span class="hljs-string">'Stock B: $155'</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h3 id="heading-best-practices-for-using-aria-live">Best Practices for Using <code>aria-live</code></h3>
<ul>
<li><p>Use <code>aria-live="polite"</code> for non-critical updates to avoid disrupting the user’s experience. Reserve <code>aria-live="assertive"</code> for urgent updates that require immediate attention, such as critical errors or security warnings.</p>
</li>
<li><p>Be mindful of how often you use <code>aria-live</code> elements on a page. Overusing it can lead to an overstimulating experience for users who rely on screen readers, as they may be overwhelmed by frequent announcements.</p>
</li>
<li><p>Don’t use <code>aria-live</code> on content that doesn’t need to be announced, or on content that’s already being communicated to the user in another way.</p>
</li>
<li><p><code>aria-live</code> is particularly useful for content that is updated dynamically, such as live sports scores, breaking news, or chat applications. Make sure that the user is kept informed of important updates as they occur.</p>
</li>
</ul>
<h2 id="heading-the-aria-roledescription-attribute">The <code>aria-roledescription</code> Attribute</h2>
<p>You can use <code>aria-roledescription</code> to provide a human-readable, localized description for the role of an element. It overrides the implicit or explicit <code>role</code> value for screen readers, and allows developers to create more intuitive and context-specific descriptions for complex or unconventional user interface components that may not have a standard role name.</p>
<p>You can use it to provide a clearer explanation of the element’s purpose or functionality.</p>
<p>In the example below, screen readers will announce it as "Bookmark Button" instead of just "Button."</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">aria-roledescription</span>=<span class="hljs-string">"Bookmark Button"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span>⭐<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span> Save this page
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>You can also use it to support internationalization, like providing role descriptions in different languages.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">aria-roledescription</span>=<span class="hljs-string">"Search Button"</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span>🔍<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span> Search
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">aria-roledescription</span>=<span class="hljs-string">"Botón de busqueda"</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"es"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span>🔍<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span> Buscar
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">aria-roledescription</span>=<span class="hljs-string">"Bouton de recherche"</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"fr"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span>🔍<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span> Recherche
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<h3 id="heading-best-practices-for-using-aria-roledescription">Best Practices for Using <code>aria-roledescription</code></h3>
<ul>
<li><p>Only use <code>aria-roledescription</code> when the standard role does not sufficiently describe the element's purpose.</p>
</li>
<li><p>The description should be short, clear, and directly related to the element's function. Avoid using jargon or overly technical language.</p>
</li>
<li><p><code>aria-roledescription</code> should be used alongside an appropriate ARIA role, not as a replacement. The <code>role</code> provides the foundational context (like <code>"button"</code> or <code>"listbox"</code>), while the description adds clarity.</p>
</li>
<li><p>If your application supports multiple languages, ensure that the <code>aria-roledescription</code> values are localized to match the user's language preferences. This helps provide a consistent and understandable experience.</p>
</li>
<li><p>Ensure that the <code>aria-roledescription</code> does not repeat or conflict with other ARIA attributes or element labels. It should complement, not duplicate, the information already provided.</p>
</li>
</ul>
<h2 id="heading-the-aria-atomic-attribute">The <code>aria-atomic</code> Attribute</h2>
<p>You can use the <code>aria-atomic</code> attribute to control how updates to an element are announced by assistive technologies. When <code>aria-atomic</code> is set to <code>true</code>, it indicates that when changes occur within the element, the entire content of the element should be treated as a single unit and announced in full by the screen reader (rather than announcing only the changed parts).</p>
<p>In cases where updates to part of an element might make the overall context unclear, <code>aria-atomic</code> helps by providing a full announcement of the element's content, giving users a complete understanding of the context.</p>
<p>It is often used in conjunction with <code>aria-live</code>. While <code>aria-live</code> determines how updates are announced (politely or assertively), <code>aria-atomic</code> controls whether the entire content is read or just the changes.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"news-ticker"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"region"</span> <span class="hljs-attr">aria-live</span>=<span class="hljs-string">"polite"</span> <span class="hljs-attr">aria-atomic</span>=<span class="hljs-string">"true"</span>&gt;</span>
  Breaking News: Major storm expected this weekend.
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"updateHeadline()"</span>&gt;</span>Update Headline<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateHeadline</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'news-ticker'</span>).innerText = <span class="hljs-string">'Breaking News: Stock market hits record high!'</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h3 id="heading-best-practices-for-using-aria-atomic">Best Practices for Using <code>aria-atomic</code></h3>
<ul>
<li><p>Apply <code>aria-atomic="true"</code> only to elements where a full announcement of updates is essential for understanding the context.</p>
</li>
<li><p>When using <code>aria-atomic="true"</code>, ensure that the content within the element provides consistent and complete context to users.</p>
</li>
<li><p>Use <code>aria-atomic</code> in combination with <code>aria-live</code> to specify how updates should be announced. This ensures that the updates are announced in the appropriate manner and with full context.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Understanding and effectively using HTML attributes for accessibility is crucial for creating inclusive web experiences. By understanding and using these attributes appropriately, you can ensure that your application has a great user experience for all visitors.</p>
<h3 id="heading-resources">Resources</h3>
<ul>
<li><p><a target="_blank" href="https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/">Providing Accessible Names and Descriptions</a></p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA">MDN ARIA</a></p>
</li>
<li><p><a target="_blank" href="https://www.w3.org/WAI/ARIA/apg/practices/read-me-first/">No ARIA is better than Bad ARIA</a></p>
</li>
<li><p><a target="_blank" href="https://www.w3.org/WAI/ARIA/apg/example-index/#examples_by_props_label">ARIA examples by properties and states</a></p>
</li>
</ul>
<p>Thank you so much for reading, I hope this guide helps you create more accessible web content. If you found it helpful, consider sharing.</p>
<p>You can connect with me on <a target="_blank" href="https://www.linkedin.com/in/elizabeth-meshioye/">LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build an Accessible Modal – with Example Code ]]>
                </title>
                <description>
                    <![CDATA[ We often use modals or popups to display important information or prompt users to take action. Unlike regular pop-ups that can be opened in new windows or tabs, these dialogues keep the user on the same page by overlaying the existing content. This e... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-an-accessible-modal-with-example-code/</link>
                <guid isPermaLink="false">66cdec7e3bcefa4703267811</guid>
                
                    <category>
                        <![CDATA[ a11y ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ frontend ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML5 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabeth Lola ]]>
                </dc:creator>
                <pubDate>Tue, 27 Aug 2024 15:10:54 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724337698676/aa23c219-2ffb-4424-bb34-3195a905d973.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>We often use modals or popups to display important information or prompt users to take action. Unlike regular pop-ups that can be opened in new windows or tabs, these dialogues keep the user on the same page by overlaying the existing content. This ensures that users remain focused on the task at hand.</p>
<p>Modals are common and sometimes required. And if they're not implemented correctly, they can be a significant barrier. Ensuring that modals are accessible means they are usable by everyone, including people who rely on assistive technologies.</p>
<p>In this article, we'll <strong>build a modal</strong> and follow the guidelines to make it accessible.</p>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>To follow along with this tutorial, you should have:</p>
<ol>
<li><p><strong>Basic HTML knowledge:</strong> Understand how HTML elements and attributes work.</p>
</li>
<li><p><strong>Basic JavaScript knowledge:</strong> Familiarity with basic JavaScript concepts like functions, event handling, and DOM manipulation is helpful.</p>
</li>
<li><p><strong>Understanding of ARIA:</strong> While the tutorial explains ARIA roles and attributes, having a basic understanding of accessibility concepts can be beneficial.</p>
</li>
</ol>
<h2 id="heading-when-should-you-use-a-modal">When Should You Use a Modal?</h2>
<p>Using modals effectively requires careful consideration of the user experience. Here are some guidelines to help you decide if you should use a modal or not:</p>
<ul>
<li><p>You should use modals when the user needs to make a critical decision, such as confirming a potentially destructive action (for example, deleting an item) or agreeing to terms and conditions</p>
</li>
<li><p>You can use a modal when a task requires the user’s complete focus and does not rely on information from the rest of the page (for example, filling out a form or completing a payment process).</p>
</li>
<li><p>You can use a modal for displaying temporary or transient information that doesn’t need to be permanently visible on the page (for example, alerts, notifications, or brief messages).</p>
</li>
<li><p>You should avoid using modals for tasks that require extensive interaction or input, such as lengthy forms or complex workflows. These can be frustrating in a modal because of limited space and navigation constraints.</p>
</li>
<li><p>You should avoid using modals for actions a user will need to perform frequently, as this can become repetitive and annoying. Inline options or tooltips might be better for repetitive actions.</p>
</li>
<li><p>You should not use modals if they interrupt the user’s natural flow on the site, especially if the content or action in the modal is not urgent or important.</p>
</li>
</ul>
<h2 id="heading-modal-accessibility-guidelines">Modal Accessibility Guidelines</h2>
<p>Here are some tips to help you build useful and accessible modals:</p>
<ul>
<li>Provide a descriptive <code>aria-labelledby</code> attribute that points to the modal's title or heading. If there is no title, use <code>aria-label</code> to provide a short, descriptive label.</li>
</ul>
<ul>
<li><p>Always include a visible and easily accessible close button within the modal, usually in the top-right corner. Label this button clearly, for example, with the text "Close" or an icon with <code>aria-label="Close"</code>.</p>
</li>
<li><p>When the modal opens, move the keyboard focus to the first interactive element within the modal (usually a close button). When the modal closes, return the focus to the element that triggered the modal.</p>
</li>
<li><p>Keep the keyboard focus within the modal while it is open.</p>
</li>
<li><p>Allow users to close the modal by pressing the <code>Escape</code> key.</p>
</li>
</ul>
<p>Following these guidelines, let's build a modal.</p>
<p>I prefer using the right HTML tags to build components, and in this case I'll be doing exactly that using the <code>dialog</code> tag.</p>
<h2 id="heading-how-to-build-a-modal-using-the-dialog-tag">How to Build a Modal Using the <code>dialog</code> Tag</h2>
<p>In case you're not familiar with the <code>dialog</code> tag, it was introduced in HTML5. You use it to create dialog boxes like popups, alerts, and modals. It offers built-in methods and attributes that make it easier to manage dialog behavior without needing extensive JavaScript. The javascript built-in methods are <code>show()</code>, <code>showModal()</code>, and <code>close()</code>.</p>
<h3 id="heading-show-and-showmodal"><code>show()</code> and <code>showModal()</code></h3>
<p>The <code>show()</code> method is useful for a non-blocking dialog. This means that the dialog appears on top of the current content, but users can still interact with other parts of the webpage (clicking buttons, links, and so on) while the dialog is open.</p>
<p>This is useful in situations where the dialog is providing information that doesn’t require the user’s immediate attention. Here's an example:</p>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!-- Previous content here --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">dialog</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"dialog-box"</span>&gt;</span>
<span class="hljs-comment">&lt;!-- More content here --&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dialog</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">const</span> dialog = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'dialog-box'</span>);
    dialog.show();
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723822375653/a592c09a-747c-4248-84e2-9cd76c8f6498.png" alt="a non-modal dialog" class="image--center mx-auto" width="1988" height="724" loading="lazy"></p>
<p>The <code>showModal()</code> method opens the dialog in a modal mode. This means that the dialog takes focus, and interaction with the rest of the webpage is blocked until the dialog is closed. The user cannot click on or interact with any other part of the page.</p>
<p>Depending on the browser, a semi-transparent backdrop appears behind the dialog, visually indicating that the rest of the page is not interactable.</p>
<p>When a dialog is opened with <code>showModal()</code>, focus is automatically trapped within the dialog. The user can only tab through elements inside the dialog, and the focus will loop within the dialog’s content until it is closed. Here's an example:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">dialog</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"dialog-box"</span>&gt;</span>
<span class="hljs-comment">&lt;!-- More content here --&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dialog</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">const</span> dialog = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'dialog-box'</span>);
    dialog.showModal();
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723823970852/1ca30713-199d-4b94-b12a-ad1a27a9063f.png" alt="a modal dialog" class="image--center mx-auto" width="1724" height="1060" loading="lazy"></p>
<p>The <code>&lt;dialog&gt;</code> element has default styles but can be customized using CSS to match your design. You can style the dialog box, add animations, or modify the backdrop. The backdrop can be styled using the <code>::backdrop</code> selector. For example:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">dialog</span><span class="hljs-selector-pseudo">::backdrop</span> {
    <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.7</span>);
}
</code></pre>
<p>The dialog also comes with some built-in accessibility features like focus management, backdrop, automatic announcement on open, and pressing the <code>ESC</code> key will close the dialog.</p>
<p>You can add the <code>autofocus</code> attribute to the first interactive element in the modal, such as the first input in a form or the close button. Alternatively, you can rely on the <code>&lt;dialog&gt;</code> element's native focus management.</p>
<p>Avoid using <code>tabindex</code> on the <code>&lt;dialog&gt;</code> element, as it is not an interactive element like a button or link. The <code>&lt;dialog&gt;</code> serves as a container for interactive content, and it is not intended to receive direct user focus.</p>
<p>The <code>&lt;dialog&gt;</code> element provides a native way to create modals. If you're building a custom modal, make sure its accessibility features match those of the native <code>&lt;dialog&gt;</code> element.</p>
<p>Bringing it all together:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
    <span class="hljs-selector-tag">dialog</span><span class="hljs-selector-pseudo">::backdrop</span> {
        <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.7</span>);
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"open-dialog"</span>&gt;</span>Open Dialog<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dialog</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"dialog-box"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Modal title<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-comment">&lt;!-- More content here --&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"close-dialog"</span> <span class="hljs-attr">autofocus</span>&gt;</span>Close<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dialog</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">const</span> dialog = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"dialog-box"</span>);
    <span class="hljs-keyword">const</span> openButton = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"open-dialog"</span>);
    <span class="hljs-keyword">const</span> closeButton = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"close-dialog"</span>);

    openButton.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">() =&gt;</span> {
      dialog.showModal();
    });
    closeButton.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">() =&gt;</span> {
      dialog.close();
    });
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<p>You'll notice that I didn't use the <code>aria-label</code> attribute on the dialog as I listed in the guidelines. Well, that's because the dialog element, if well-structured, doesn't necessarily need one. In this case, there's a visible label in the dialog element (the <code>h2</code> element).</p>
<p>If there are no visible labels present then you need to add one. Like in this example:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">dialog</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"confimation-dialog"</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Confirmation Dialog"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Are you sure you want to proceed?<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"close-dialog"</span> <span class="hljs-attr">autofocus</span>&gt;</span>Close<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dialog</span>&gt;</span>
</code></pre>
<h2 id="heading-what-is-the-inert-attribute">What is the <code>inert</code> Attribute?</h2>
<p>When a modal is open, a screen reader might still navigate to and around content outside the modal. You would generally want the user's focus to be restricted to the modal itself, or stop the user from accidentally clicking on elements outside the modal to prevent confusion and errors. In these cases, you'll need the <code>inert</code> attribute.</p>
<p>The <code>inert</code> attribute makes an element and all of its descendants non-interactive and inaccessible to assistive technologies. When a modal is open, using the <code>inert</code> attribute on the rest of the page content will ensure that only the modal content can be accessed, making the dialog experience clearer.</p>
<h3 id="heading-how-to-use-the-inert-attribute">How to Use the <code>inert</code> Attribute</h3>
<p>When a modal is opened, you can apply the <code>inert</code> attribute to the rest of the page content (typically the <code>&lt;main&gt;</code> element). When the modal is closed, you remove the <code>inert</code> attribute.</p>
<p>Here's an example showing how to use <code>inert</code> with a modal dialog:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>Site Header<span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"main-content"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"open-dialog"</span>&gt;</span>Open modal<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is the main content of the page.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- More content here --&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Move the dialog outside the main element --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dialog</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"dialog"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Modal Title<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is the content inside the modal.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"close-dialog"</span> <span class="hljs-attr">autofocus</span>&gt;</span>Close<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dialog</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
        <span class="hljs-keyword">const</span> dialog = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'dialog'</span>);
        <span class="hljs-keyword">const</span> mainContent = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'main-content'</span>);
        <span class="hljs-keyword">const</span> openButton = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'open-dialog'</span>);
        <span class="hljs-keyword">const</span> closeButton = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'close-dialog'</span>);

        openButton.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">() =&gt;</span> {
           mainContent.setAttribute(<span class="hljs-string">'inert'</span>, <span class="hljs-string">''</span>);
          dialog.showModal();
        });

        closeButton.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">() =&gt;</span> {
           dialog.close();
        });

        <span class="hljs-comment">// the dialog elemnt has a close event, which is called when a user calls the close() method or presses the esc key</span>
        dialog.addEventListener(<span class="hljs-string">"close"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
           mainContent.removeAttribute(<span class="hljs-string">"inert"</span>);
        });
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<h2 id="heading-how-to-animate-the-open-and-close-states">How to Animate the Open and Close States</h2>
<p>When a modal appears (open state) or disappears (close state), it can be jarring for users if this transition happens abruptly. Animating these states can create a smoother user experience by gradually introducing or removing the modal, making it feel more natural.</p>
<h4 id="heading-why-animate-the-open-and-close-states">Why Animate the Open and Close States?</h4>
<p>Animating the open and close states of a modal can:</p>
<ul>
<li><p><strong>Enhance User Experience</strong>: A smooth animation can make the transition less abrupt and more engaging.</p>
</li>
<li><p><strong>Draw Attention</strong>: Subtle animations can help guide the user's focus to the modal content when it appears.</p>
</li>
<li><p><strong>Maintain Consistency</strong>: Consistent animations across your UI can create a cohesive and professional feel.</p>
</li>
</ul>
<p>By default, the dialog is set to <code>display:none</code> when closed and <code>display:block</code> when open. You cannot transition from <code>none</code> to <code>block</code> in CSS, but you can combine the display properties with <code>transform</code> or <code>opacity</code>. The <code>transform</code> property can be used to scale or move the modal, while <code>opacity</code> controls its transparency.</p>
<p>Here’s an example of how you might animate a modal:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">dialog</span> {
  <span class="hljs-attribute">animation</span>: zoom-out <span class="hljs-number">0.5s</span> ease-out;
}

<span class="hljs-comment">/* an open attribute is added to the dialog when it is open  */</span>
<span class="hljs-selector-tag">dialog</span><span class="hljs-selector-attr">[open]</span> {
    <span class="hljs-attribute">animation</span>: zoom-in <span class="hljs-number">0.5s</span> ease-out;
}

<span class="hljs-comment">/* The display property in the keyframes is critical 
because it toggles the modal’s visibility on and off.  */</span>
<span class="hljs-keyword">@keyframes</span> zoom-in {
    0% {
      <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
      <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">0.1</span>);
      <span class="hljs-attribute">display</span>:  none;
    }
    100% {
      <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
      <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1</span>);
      <span class="hljs-attribute">display</span>: block;
    }
}

<span class="hljs-keyword">@keyframes</span> zoom-out {
    0% {
      <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
      <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1</span>);
      <span class="hljs-attribute">display</span>: block;
    }
    100% {
      <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
      <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">0</span>);
      <span class="hljs-attribute">display</span>: none;
    }
}
</code></pre>
<p>Final result:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/leezee/embed/preview/XWLVBgp?default-tab=result&amp;editable=true" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The <code>&lt;dialog&gt;</code> element is the native way to create modals. It provides built-in accessible features for both keyboard and screen reader users</p>
<p>The <code>&lt;dialog&gt;</code> element is of two types, modal and non-modal. You can create a non-modal dialog using the <code>show()</code> method, and the <code>showModal()</code> method will create a modal dialog.</p>
<p>When you're not using the native dialog element, ensure your custom modal matches the native dialog in terms of accessibility to ensure a uniform experience for all users</p>
<p>You should also always remember to autofocus the most immediate interactive element, the dialog can do this by default.</p>
<p>Finally, you can use the <code>inert</code> attribute on other elements to prevent those elements from being accessed when the modal is open.</p>
<h3 id="heading-resources">Resources:</h3>
<ul>
<li><p><a target="_blank" href="https://w3c.github.io/aria/#dialog">W3c Dialog role</a></p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog">MDN: The Dialog element</a></p>
</li>
</ul>
<p>Thank you so much for reading this article. If you found it helpful, consider sharing. Happy coding!</p>
<p>You can connect with me on <a target="_blank" href="https://www.linkedin.com/in/elizabeth-meshioye/">LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is Motion Sensitivity? How to Design Accessible Web Animations ]]>
                </title>
                <description>
                    <![CDATA[ As web developers, we love a good animation, right? But let's be honest, sometimes we get caught up in the wow factor and forget that our websites exist for real people with diverse needs.  One hidden hurdle for some users is motion sensitivity. It m... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/web-sensitivity-how-to-design-accessible-animations/</link>
                <guid isPermaLink="false">66bb8c556b3bd8d6bf25ae5d</guid>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Design ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabeth Lola ]]>
                </dc:creator>
                <pubDate>Wed, 07 Feb 2024 21:51:54 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/pexels-pixabay-315938-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As web developers, we love a good animation, right? But let's be honest, sometimes we get caught up in the wow factor and forget that our websites exist for real people with diverse needs. </p>
<p>One hidden hurdle for some users is motion sensitivity. It might not be something we think about every day, but it can have a big impact on how people experience the internet.</p>
<p>In this article, I want to shine a light on <strong>motion sensitivity</strong>. We'll explore what it's like, the conditions it's linked to, and how it can affect someone's ability to enjoy using a website. </p>
<p>My goals for this article are: </p>
<ol>
<li>To get you thinking about creating web experiences that are comfortable and welcoming for everyone. </li>
<li>To equip you with practical tips to make that happen. Because an inclusive web is a better web for everyone.</li>
</ol>
<h2 id="heading-what-is-motion-sensitivity">What is Motion Sensitivity?</h2>
<p>Motion sensitivity isn't just a technical term – it refers to how we experience the digital world, especially for those whose sensitivities go beyond what meets the eye. So, let's unravel this concept and see why it matters.</p>
<p>According to <a target="_blank" href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7418000/#:~:text=Motion%20sensitivity%20is%20characterized%20by,dizziness%20%5B1%2D3%5D.">National Library of Medicine</a>, motion sensitivity refers to a condition where a person experiences symptoms such as dizziness, nausea, and imbalance in response to motion. This can be caused by a variety of factors, including inner ear problems, neurological disorders, and certain medications. </p>
<p>People with motion sensitivity may have difficulty tolerating activities that involve moving, such as riding in cars and even certain motion animations.</p>
<p>Maybe you've taken a long road trip and experienced motion sickness. Or you've visited the cinema to see a 3D movie and, instead of enjoying the experience, you end up with headaches, migraine, dizziness, or nausea. Then you understand how serious motion sensitivity can be.</p>
<h3 id="heading-how-motion-sensitivity-impacts-people">How Motion Sensitivity Impacts People</h3>
<p>For some people, motion effects like parallax scrolling can be annoying, but the effects of motion sensitivity go beyond a mere inconvenience. It can disrupt the digital experience and, more importantly, affect the well-being of those navigating the space. </p>
<p>Some people might feel dizzy, nauseous, or experience headaches or migraines when faced with certain animations or transitions. For them, accessing digital content becomes more than just a click – it's a consideration of their comfort and health.</p>
<h3 id="heading-insights-into-related-disorders">Insights into Related Disorders</h3>
<p>To truly understand motion sensitivity, I believe we need to explore the conditions linked to it, mainly vestibular disorders and visual motion sensitivity.</p>
<p><strong>Vestibular Disorders</strong> impact the inner ear and how the brain processes spatial information. For someone with vestibular disorders, simple tasks like maintaining balance or handling motion stimuli can become challenging.</p>
<p><strong>Visual Motion Sensitivity</strong> is about heightened sensitivity to visual stimuli, leading to discomfort or adverse reactions to certain types of motion. For someone with visual motion sensitivity, navigating websites with specific animations or scrolling behaviors can be a struggle.</p>
<p>By diving into these facets of motion sensitivity, we lay the groundwork for creating digital spaces that acknowledge and respect diverse user experiences. </p>
<h3 id="heading-so-why-does-this-matter">So, Why Does this Matter?</h3>
<p>Well, I think it is as simple as this: everyone deserves to enjoy the digital world without feeling unwell. Understanding motion sensitivity helps us create websites, games, and apps that are more inclusive and comfortable for everyone, not just folks with superhero vision.</p>
<p>Let's explore why designing with motion sensitivity in mind is not just a best practice but a step towards a more inclusive online world.</p>
<h3 id="heading-how-common-is-motion-sensitivity">How Common is Motion Sensitivity?</h3>
<p>Motion sensitivity is more common than you might think. According to <a target="_blank" href="https://archivesphysiotherapy.biomedcentral.com/articles/10.1186/s40945-020-00077-9#:~:text=It%20has%20been%20reported%20that,men%20%5B2%2C%203%5D.">this article</a> from Archives of Physiotherapy, it has been reported that 28.4% of the population experience motion sensitivity. Also, according to <a target="_blank" href="https://en.wikipedia.org/wiki/Motion_sickness#:~:text=of%20motion%20sickness.-,Epidemiology,medium%20to%20high%20motion%20sickness.">this article</a>:</p>
<blockquote>
<p>Nearly all people are affected with sufficient motion and most people will experience motion sickness at least once in their lifetime. Susceptibility, however, is variable, with about one-third of the population being highly susceptible while most other people are affected under extreme conditions. Women are more easily affected than men. </p>
</blockquote>
<p>These statistics underscore the need for web designers and developers to consider motion sensitivity in our creations. They highlight that what might be a visually engaging animation for one user could be an obstacle for another.</p>
<h2 id="heading-how-to-identify-motion-sensitive-triggers-in-animations">How to Identify Motion-Sensitive Triggers in Animations</h2>
<p>Animation can enhance engagement and help guide users through the app. But it is vital that we scrutinize the types of animations we incorporate into our designs, particularly when aiming for motion-friendly experiences. </p>
<p>Let's explore these potential triggers and discuss alternatives to ensure a more inclusive design.</p>
<h3 id="heading-rapid-or-flickering-animations">Rapid or Flickering Animations</h3>
<ul>
<li><strong>Trigger Potential:</strong> Quick, flickering animations can be disorienting for users with motion sensitivity, leading to discomfort or headaches. Examples of these types of animations include rapidly blinking notifications, flickering banners, or flashing call-to-action buttons.</li>
<li><strong>Alternative Approach:</strong> Opt for smoother transitions like subtle fades or slides, avoiding rapid flickering effects for a more comfortable experience.</li>
</ul>
<h3 id="heading-overly-complex-transitions">Overly Complex Transitions</h3>
<ul>
<li><strong>Trigger Potential</strong>: Elaborate loading animations with intricate patterns, complex slide-in effects, or overly detailed transitions between pages may overwhelm users, causing sensory overload for those with motion sensitivity.</li>
<li><strong>Alternative Approach</strong>: Simplify transitions, focus on clarity and purpose. Strive for elegance in design without unnecessary visual complexity.</li>
</ul>
<h3 id="heading-bouncing-or-elastic-motions">Bouncing or Elastic Motions</h3>
<ul>
<li><strong>Trigger Potential</strong>: Animations with bouncing or elastic movements can induce dizziness or nausea in motion-sensitive users. Examples include buttons that bounce upon interaction or elastic-scrolling effects.</li>
<li><strong>Alternative Approach</strong>: Choose more subtle easing functions for animations, providing a smoother and less physically demanding experience.</li>
</ul>
<h3 id="heading-high-speed-animations">High-Speed Animations</h3>
<ul>
<li><strong>Trigger Potential</strong>: High-speed carousels, rapid image sliders, or quick-scrolling features may challenge users with motion sensitivity, potentially leading to feelings of discomfort or disorientation.</li>
<li><strong>Alternative Approach</strong>: Allow users to control animation speeds or default to slower, more deliberate transitions for a universally comfortable pace.</li>
</ul>
<h3 id="heading-continuous-auto-scrolling">Continuous Auto-Scrolling</h3>
<ul>
<li><strong>Trigger Potential</strong>: Auto-scrolling features that move content continuously without user interaction, like automatic slideshows or news tickers, can be unsettling for users with motion sensitivity.</li>
<li><strong>Alternative Approach</strong>: Implement user-initiated scrolling, providing control to the user and avoiding unexpected motion.</li>
</ul>
<h3 id="heading-flashing-or-intense-color-changes">Flashing or Intense Color Changes</h3>
<ul>
<li><strong>Trigger Potential</strong>: Flashing animations or sudden, intense color changes can be visually overwhelming and trigger discomfort. Examples include flashing banners, intense color changes on hover, or rapidly changing background colors.</li>
<li><strong>Alternative Approach</strong>: Maintain a consistent color palette and avoid rapid, drastic color shifts. Consider softer transitions for color changes.</li>
</ul>
<h3 id="heading-rotational-movements">Rotational Movements</h3>
<ul>
<li><strong>Trigger Potential</strong>: Rotational animations, such as spinning logos or rotating carousels, may cause dizziness or vertigo for individuals with vestibular disorders or motion sensitivity.</li>
<li><strong>Alternative Approach</strong><em>:</em> Minimize or eliminate rotational motions, especially in situations where they may not be essential for understanding the content.</li>
</ul>
<p>By recognizing these potential triggers and adopting alternative approaches, we can create digital experiences that are more considerate and welcoming for users with motion sensitivity. </p>
<p>The goal is not to stop adding animations but to design with empathy, ensuring that motion enhances rather than detracts from the user experience.</p>
<h2 id="heading-how-to-use-reduce-motion-preferences">How to Use Reduce-Motion Preferences</h2>
<p>One significant stride towards motion-friendly web design is utilizing the <code>reduce-motion</code> preferences embedded in operating systems and browsers. This preference provide users with the option to minimize or eliminate unnecessary animations. </p>
<p>By recognizing and respecting these user preferences, we can significantly enhance the accessibility of web applications.</p>
<h3 id="heading-incorporate-reduced-motion-features">Incorporate Reduced Motion Features</h3>
<p>For developers, integrating reduced motion features into web applications involves a combination of coding practices and user interface considerations. </p>
<p>Begin by identifying areas where animations can be toned down or replaced with static alternatives. Implementing conditional checks for reduce-motion preferences in your codebase allows your web application to adapt dynamically, providing a smoother experience for users who opt for reduced motion.</p>
<h4 id="heading-css-prefers-reduced-motion-media-feature">CSS prefers-reduced-motion Media Feature</h4>
<pre><code class="lang-css"><span class="hljs-selector-class">.animated-element</span> {
  <span class="hljs-attribute">animation</span>: pulse <span class="hljs-number">1s</span> linear infinite both;
}

<span class="hljs-comment">/* Tone down the animation */</span>
<span class="hljs-keyword">@media</span> (prefers-reduced-motion) {
  <span class="hljs-selector-class">.animated-element</span> {
    <span class="hljs-attribute">animation</span>: smooth <span class="hljs-number">4s</span> linear infinite both;
  }
}
</code></pre>
<h4 id="heading-javascript-reduced-motion-detection">JavaScript Reduced Motion Detection</h4>
<pre><code class="lang-js"><span class="hljs-comment">// Check if the user prefers reduced motion using JavaScript</span>

<span class="hljs-keyword">const</span> prefersReducedMotion = <span class="hljs-built_in">window</span>.matchMedia(<span class="hljs-string">'(prefers-reduced-motion: reduce)'</span>).matches;

<span class="hljs-comment">// Example of adjusting animation based on reduced motion preference</span>

<span class="hljs-keyword">const</span> animatedElement = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.animated-element'</span>);
<span class="hljs-keyword">if</span> (prefersReducedMotion) {
  animatedElement.style.animation = <span class="hljs-string">'smooth 4s linear infinite both'</span>;
} <span class="hljs-keyword">else</span> {
  animatedElement.style.animation = <span class="hljs-string">'pulse 1s linear infinite both'</span>;
}
</code></pre>
<h3 id="heading-test-your-animation-on-chrome">Test Your Animation on Chrome</h3>
<p>While basic accessibility checks are readily available, Chrome DevTools offers advanced capabilities through its hidden <strong>Rendering</strong> tool. </p>
<p>One of the options available in the rendering tool is the option to test your animation for when a user enables <code>prefers-reduced-motion</code>. Here's how to leverage it:</p>
<ul>
<li>Click the customize (three dots) icon in the DevTools panel</li>
<li>Select more tools</li>
<li>Select <strong>Rendering</strong> option from the list of options</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Screenshot-2024-02-07-at-10.44.34.png" alt="The chrome dev tool" width="600" height="400" loading="lazy">
<em>Select Rendering under more tools</em></p>
<ul>
<li>Once enabled, the <strong>Rendering</strong> tab appears in DevTools.</li>
<li>Look for the option named "<strong>Emulate CSS media feature prefers-reduced-motion</strong>."</li>
<li>Enable this option to preview how your website's animations appear for users who have set their device or browser to reduce motion.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Screenshot-2024-02-07-at-10.51.13.png" alt="Chrome rendering tool for reduced-motion" width="600" height="400" loading="lazy"></p>
<p>When a user has <code>prefers-reduced-motion</code> enabled, avoid completely removing animations. Aim to provide users with a smoother experience rather than completely excluding them from the interactive experience.</p>
<h2 id="heading-motion-sensitivity-tips-and-best-practices">Motion Sensitivity Tips and Best Practices</h2>
<p>Let's explore tips and best practices to incorporate into our designs:</p>
<ol>
<li><strong>Subtle Animations:</strong> Opt for subtle animations that convey information without being overwhelming. Gentle fades, transitions, and loading effects can enhance the user experience without causing discomfort.</li>
<li><strong>Adjustable Speeds:</strong> Provide users with the ability to control animation speeds. Implement settings within your application that allow users to customize the speed of transitions, ensuring a comfortable experience for everyone.</li>
<li><strong>Clear Navigation Signals:</strong> Use motion to guide users intuitively. For instance, employ subtle animations to indicate a change in state or to draw attention to important elements, ensuring that users with motion sensitivity can follow the flow without feeling disoriented.</li>
<li><strong>User Testing:</strong> Conduct thorough user testing, specifically with individuals who experience motion sensitivity. Gather feedback to refine your design, ensuring that it meets the needs of the diverse user base.</li>
<li><strong>Document and Communicate:</strong> Clearly document your approach to motion-friendly design in your project documentation. This not only serves as a reference for your team but also communicates your commitment to accessibility to stakeholders and users.</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Motion sensitivity isn't a rare exception – it's a shared experience for many people. Our responsibility as web developers is not merely to acknowledge this reality but to actively integrate inclusivity into the DNA of our creations.</p>
<p>By identifying potential triggers and implementing reduced motion features using technologies like <code>prefers-reduced-motion</code> in CSS and JavaScript, we create spaces that accommodate diverse needs without compromising on engagement. </p>
<p>Accessibility is not a trend, it's a fundamental ethos that shapes the future of the internet into one where everyone regardless of their abilities can use the internet with comfort.</p>
<p>Thank you so much for reading this article, if you found it helpful consider sharing. Happy coding!</p>
<p>You can connect with me on <a target="_blank" href="https://www.linkedin.com/in/elizabeth-meshioye/">LinkedIn</a> or <a target="_blank" href="https://github.com/Lezette">GitHub</a>.</p>
<h3 id="heading-references">References</h3>
<ul>
<li>Val Head. Designing Safer Web Animation For Motion Sensitivity (September 08, 2015) https://alistapart.com/article/designing-safer-web-animation-for-motion-sensitivity/</li>
<li>Chaudhary, S., Saywell, N., Kumar, A., &amp; Taylor, D. (2020). Visual Fixations and Motion Sensitivity: Protocol for an Exploratory Study. JMIR Research Protocols, 9(7). https://doi.org/10.2196/16805</li>
<li>Albalwi, A.A., Johnson, E.G., Alharbi, A.A. et al. Effects of head motion on postural stability in healthy young adults with chronic motion sensitivity. Arch Physiother10, 6 (2020). https://doi.org/10.1186/s40945-020-00077-9</li>
<li>Motion sickness. (2024, January 1). In Wikipedia. https://en.wikipedia.org/wiki/Motion_sickness</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build an Accessible Custom Dropdown Select Element ]]>
                </title>
                <description>
                    <![CDATA[ Sometimes you might want to use a different select element to match your style based on the theme of your design. Or perhaps the default design is different on separate browsers and you want uniformity.  But when designing this new element, you might... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-an-accessible-custom-dropdown-select-element/</link>
                <guid isPermaLink="false">66bb8c53c332a9c775d15b71</guid>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabeth Lola ]]>
                </dc:creator>
                <pubDate>Thu, 04 Jan 2024 17:06:29 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/a11y-select.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Sometimes you might want to use a different select element to match your style based on the theme of your design. Or perhaps the default design is different on separate browsers and you want uniformity. </p>
<p>But when designing this new element, you might forget to consider the accessibility of the component. </p>
<p>Typically, default elements are accessible – and if you plan to replace them with custom designs, you should ensure it works as well as the default.</p>
<p>In this tutorial, I'll show you how to build a custom dropdown with a step by step example.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this tutorial, you should have:</p>
<ol>
<li><strong>Basic HTML knowledge:</strong> Understand how HTML elements and attributes work.</li>
<li><strong>Basic JavaScript knowledge:</strong> Familiarity with basic JavaScript concepts like functions, event handling, and DOM manipulation is helpful.</li>
<li><strong>Understanding of ARIA:</strong> While the tutorial explains ARIA roles and attributes, having a basic understanding of accessibility concepts can be beneficial.</li>
</ol>
<h2 id="heading-heres-what-well-cover">Here's What We'll Cover:</h2>
<ol>
<li><a class="post-section-overview" href="#heading-default-select-features">Default Select Features</a></li>
<li><a class="post-section-overview" href="#heading-how-to-figure-out-which-aria-attributes-are-required">How to Figure Out Which ARIA Attributes Are Required</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-html">How to Set Up the HTML</a></li>
<li><a class="post-section-overview" href="#heading-the-css">The CSS</a></li>
<li><a class="post-section-overview" href="#heading-the-javascript">The JavaScript</a><br>– <a class="post-section-overview" href="#heading-toggle-dropdown-visibility">Toggle dropdown visibility</a><br>– <a class="post-section-overview" href="#heading-closing-the-dropdown-using-the-esc-key">How to close the dropdown</a><br>– <a class="post-section-overview" href="#heading-dropdown-keyboard-interaction">Dropdown keyboard interaction</a><br>– <a class="post-section-overview" href="#heading-fixing-option-visibility-issue">How to fix the option visibility issue</a><br>– <a class="post-section-overview" href="#heading-highlighting-options-on-alphanumeric-key-press">How to highlight options on alphanumeric keypress</a><br>– <a class="post-section-overview" href="#heading-enhancing-screen-reader-functionality">How to enhance screenreader functionality</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></li>
</ol>
<h2 id="heading-default-select-features">Default Select Features</h2>
<p>Since the default select attribute is accessible, let's look at some of the features that makes it accessible:</p>
<ul>
<li>The select element visibly indicates when it's active or selected, typically through a change in appearance.</li>
<li>The element opens on click or key press (SPACE, UP, and DOWN Arrow)</li>
<li>While the dropdown is open, users can move through the available options by pressing the UP or DOWN arrow keys.</li>
<li>Entering alphanumeric keys when the dropdown is open highlights the option that matches the entered letters. If there's no match, nothing changes.</li>
<li>Clicking on an option or pressing SPACE or ENTER when an option is highlighted selects that option, updates the select value, and closes the dropdown.</li>
<li>If the dropdown is open, pressing the ESC key closes it, providing a quick way to cancel the selection or close the dropdown.</li>
<li>When the select element is focused when using a screen reader, the screen reader announces that it's a select element and provides information about the currently selected value for accessibility.</li>
</ul>
<p>Using this information, let's build a custom dropdown.</p>
<h2 id="heading-how-to-figure-out-which-aria-attributes-are-required">How to Figure Out Which ARIA Attributes Are Required</h2>
<p>While some elements' roles and accessible names are obvious, there are some that aren't. Whenever I need to find the appropriate role or ARIA-attibute for a component, I check out the <a target="_blank" href="https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/#accessiblenameguidancebyrole">W3 accessible names</a> guide. </p>
<p>In this case, I know the custom dropdown should have a <code>role="options"</code> but I don't know what role to assign the parent elements. </p>
<p>So to start, I locate the option <strong>Accessible Name Guidance by Role</strong> list. You can see that the Option is pointing to a combobox pattern.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/image-74.png" alt="Option list in the Accessible Name Guidance by Role table" width="600" height="400" loading="lazy">
<em>The option in the table is showing a combobox.</em></p>
<p>The next thing I need to do is to read more on the combobox. According to t<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/combobox_role#examples">his MDN page</a> I understand that a combobox is a component that combines an input type element with a dropdown list and allows users to select from a list of options presented in the dropdown.</p>
<p>That sounds exactly like what the select element does. The combobox also needs to have an <code>[aria-expanded](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-expanded)</code> attribute and a connecting popup element which will contain the list of options. According to the MDN page:</p>
<blockquote>
<p>The popup element associated with a <code>combobox</code> can be either a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/listbox_role"><code>listbox</code></a>, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tree_role"><code>tree</code></a>, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/grid_role"><code>grid</code></a>, or <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/dialog_role"><code>dialog</code></a> element.</p>
</blockquote>
<p>In this example, we'll be using a <code>listbox</code> element.</p>
<p>The combobox element needs to have an <code>aria-contols</code> and <code>aria-haspopup</code> attributes, the value of these attributes will be the ID of the <code>listbox</code> element. </p>
<h2 id="heading-how-to-set-up-the-html">How to Set Up the HTML</h2>
<p>From the information gathered we will need a <code>combobox</code>, <code>listbox</code>, and <code>option</code> to setup our HTML.</p>
<p>In this example, the HTML will look like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"select"</span>&gt;</span>Custom Select box<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
     <span class="hljs-attr">role</span>=<span class="hljs-string">"combobox"</span>
     <span class="hljs-attr">id</span>=<span class="hljs-string">"select"</span>
     <span class="hljs-attr">value</span>=<span class="hljs-string">"Select"</span>
     <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"listbox"</span>
     <span class="hljs-attr">aria-haspopup</span>=<span class="hljs-string">"listbox"</span>
     <span class="hljs-attr">tabindex</span>=<span class="hljs-string">"0"</span>
     <span class="hljs-attr">aria-expanded</span>=<span class="hljs-string">"false"</span>&gt;</span>
    Select<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"listbox"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"listbox"</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"option"</span>&gt;</span>Option 1<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"option"</span>&gt;</span>Option 2<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"option"</span>&gt;</span>Option 3<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>In the code above, the button has a <code>role="combobox"</code> and according to the MDN combobox article the <code>[aria-expanded](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-expanded)</code> attribute is required when working with a combobox. The <code>aria-controls</code> points to the id of the listbox which is <code>listbox</code>. This associates the listbox with the combobox. </p>
<h2 id="heading-the-css">The CSS</h2>
<p>You can style the dropdown anyhow you want based on your requirements. Here's a sample style for my component:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.form</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">1.2rem</span> <span class="hljs-number">0</span>;
  <span class="hljs-attribute">position</span>: relative;
  <span class="hljs-selector-id">#announcement</span> {
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
  }
  <span class="hljs-selector-tag">label</span> {
    <span class="hljs-attribute">display</span>: block;
    <span class="hljs-attribute">padding</span>: .<span class="hljs-number">7rem</span> .<span class="hljs-number">8rem</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">65%</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
    <span class="hljs-attribute">text-align</span>: left;
    <span class="hljs-attribute">font-size</span>: .<span class="hljs-number">75rem</span>;
  }
  <span class="hljs-selector-tag">button</span>,
  <span class="hljs-selector-tag">ul</span>{
    <span class="hljs-attribute">display</span>: block;
    <span class="hljs-attribute">padding</span>: .<span class="hljs-number">7rem</span> .<span class="hljs-number">8rem</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">60%</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
    <span class="hljs-attribute">text-align</span>: left;
    <span class="hljs-attribute">background</span>: white;
    <span class="hljs-attribute">border</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  }
  <span class="hljs-selector-tag">button</span>{
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">justify-content</span>: space-between;
    <span class="hljs-attribute">align-items</span>: center;
    <span class="hljs-attribute">position</span>: relative;

    &amp;<span class="hljs-selector-pseudo">::before</span> {
      <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Font Awesome 5 Free"</span>;
      <span class="hljs-attribute">content</span>: <span class="hljs-string">"\f107"</span>;
      <span class="hljs-attribute">vertical-align</span>: middle;
      <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">900</span>;
      <span class="hljs-attribute">position</span>: absolute;
      <span class="hljs-attribute">right</span>: .<span class="hljs-number">8rem</span>;
    }

    &amp;<span class="hljs-selector-pseudo">:focus</span>-visible {
      <span class="hljs-attribute">outline</span>: <span class="hljs-number">0</span>;
      <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">5px</span> <span class="hljs-number">2px</span> rgba(<span class="hljs-number">251</span>, <span class="hljs-number">146</span>, <span class="hljs-number">60</span>, <span class="hljs-number">0.7</span>) inset;
    }
  }
  <span class="hljs-selector-tag">ul</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#3f403b</span>;
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">right</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">4.8rem</span>;
    <span class="hljs-attribute">max-height</span>: <span class="hljs-number">10rem</span>;
    <span class="hljs-attribute">overflow-y</span>: auto;
    <span class="hljs-attribute">list-style-type</span>: none;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">margin-top</span>: .<span class="hljs-number">1rem</span>;
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">transform</span>: scale(<span class="hljs-number">1</span>,<span class="hljs-number">0</span>);
    <span class="hljs-attribute">transform-origin</span>: top left;
    <span class="hljs-attribute">transition</span>: all .<span class="hljs-number">3s</span> ease-in;
    <span class="hljs-attribute">pointer-events</span>: none;
    <span class="hljs-attribute">z-index</span>: <span class="hljs-number">2</span>;
    &amp;<span class="hljs-selector-class">.active</span> {
      <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
      <span class="hljs-attribute">transform</span>: scale(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>);
      <span class="hljs-attribute">pointer-events</span>: auto;
    }
    <span class="hljs-selector-tag">li</span> {
      <span class="hljs-attribute">padding</span>: .<span class="hljs-number">6rem</span> .<span class="hljs-number">5rem</span>;
      <span class="hljs-attribute">border-top</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#e6e6e6</span>;
      <span class="hljs-attribute">cursor</span>: pointer;
      <span class="hljs-attribute">transition</span>: all .<span class="hljs-number">3s</span> ease-in;
      <span class="hljs-attribute">position</span>: relative;
      &amp;<span class="hljs-selector-pseudo">::before</span> {
        <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Font Awesome 5 Free"</span>;
        <span class="hljs-attribute">content</span>: <span class="hljs-string">"\f00c"</span>;
        <span class="hljs-attribute">vertical-align</span>: middle;
        <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">900</span>;
        <span class="hljs-attribute">position</span>: absolute;
        <span class="hljs-attribute">right</span>: .<span class="hljs-number">8rem</span>;
        <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
        <span class="hljs-attribute">transition</span>: opacity .<span class="hljs-number">300s</span> ease-out;
      }
      &amp;<span class="hljs-selector-pseudo">:hover</span>, &amp;<span class="hljs-selector-class">.current</span> {
        <span class="hljs-attribute">background</span>: <span class="hljs-number">#e6e6e6</span>;
      }
      &amp;<span class="hljs-selector-class">.active</span> {
        <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">2px</span> rgba(<span class="hljs-number">251</span>, <span class="hljs-number">146</span>, <span class="hljs-number">60</span>, <span class="hljs-number">0.7</span>);
      }
      &amp;<span class="hljs-selector-class">.active</span><span class="hljs-selector-pseudo">::before</span> {
        <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
      }
    }
  }
}
</code></pre>
<p>In the code above, I have hidden the listbox element and added an active class that shows it. I have also added a current class that styles the highlighted option and an active class that styles the selected option.</p>
<p>This is how it looks:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/image-80.png" alt="Downdown list with options" width="600" height="400" loading="lazy">
<em>The current state and active state of an option</em></p>
<h2 id="heading-the-javascript">The Javascript</h2>
<p>It's easier to break down the features and work on them one at a time, and that's what we'll do here.</p>
<h3 id="heading-toggle-dropdown-visibility">Toggle Dropdown Visibility</h3>
<p>Clicking the combobox or pressing the <code>Space</code> or <code>Enter</code> keys on the keyboard (when the button is focused) should toggle the dropdown visibility:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> elements = {
  <span class="hljs-attr">button</span>: <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'[role="combobox"]'</span>),
  <span class="hljs-attr">dropdown</span>: <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'[role="listbox"]'</span>),
}; <span class="hljs-comment">// I like to group all my elements into one objects 🤓.</span>
<span class="hljs-keyword">let</span> isDropdownOpen = <span class="hljs-literal">false</span>;

<span class="hljs-keyword">const</span> toggleDropdown = <span class="hljs-function">() =&gt;</span> {
  elements.dropdown.classList.toggle(<span class="hljs-string">'active'</span>);
  isDropdownOpen = !isDropdownOpen;
  elements.button.setAttribute(<span class="hljs-string">'aria-expanded'</span>, isDropdownOpen.toString()); <span class="hljs-comment">// update the aria-expanded state</span>
};

<span class="hljs-keyword">const</span> handleKeyPress = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
   event.preventDefault();
  <span class="hljs-keyword">const</span> { key } = event;
  <span class="hljs-keyword">const</span> openKeys = [<span class="hljs-string">'Enter'</span>, <span class="hljs-string">' '</span>];

  <span class="hljs-keyword">if</span> (openKeys.includes(key)) {
    toggleDropdown();
  }
};

elements.button.addEventListener(<span class="hljs-string">'keydown'</span>, handleKeyPress);
elements.button.addEventListener(<span class="hljs-string">'click'</span>, toggleDropdown);
</code></pre>
<p>In the code above we've created a toggleable dropdown button that responds to both keyboard and mouse interactions. The <code>toggleDropdown</code> function adds an <code>active</code> class to the dropdown.</p>
<h3 id="heading-closing-the-dropdown-using-the-esc-key">Closing the Dropdown: Using the Esc Key</h3>
<p>Pressing the Esc key or clicking outside the dropdown element should close the dropdown:</p>
<pre><code class="lang-js"><span class="hljs-comment">// previous code</span>

<span class="hljs-comment">// update handleKeyPress function </span>
<span class="hljs-keyword">const</span> handleKeyPress = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    event.preventDefault();
  <span class="hljs-keyword">const</span> { key } = event;
  <span class="hljs-keyword">const</span> openKeys = [<span class="hljs-string">'Enter'</span>, <span class="hljs-string">' '</span>];

  <span class="hljs-keyword">if</span> (!isDropdownOpen &amp;&amp; openKeys.includes(key) || (isDropdownOpen &amp;&amp; key === <span class="hljs-string">'Escape'</span>)) {
    toggleDropdown();

  }
};

<span class="hljs-keyword">const</span> handleDocumentInteraction = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> isClickInsideButton = elements.button.contains(event.target);
  <span class="hljs-keyword">const</span> isClickInsideDropdown = elements.dropdown.contains(event.target);

  <span class="hljs-keyword">if</span> (isClickInsideButton || (!isClickInsideDropdown &amp;&amp; isDropdownOpen)){
    toggleDropdown();
  }
};


elements.button.addEventListener(<span class="hljs-string">'keydown'</span>, handleKeyPress);
<span class="hljs-comment">// elements.button.addEventListener('click', toggleDropdown);</span>
<span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">'click'</span>, handleDocumentInteraction);
</code></pre>
<p>While it might seem like the <code>handleKeyPress</code> and <code>handleDocumentInteraction</code> functions could be combined for simplicity, we'll keep them separate as these functions will handle more tasks later in the article.</p>
<p>In the code above we have updated the <code>handleKeyPress</code> function to check for <code>Escape</code> and also introduced a <code>handleDocumentInteraction</code> function to close the dropdown if there's a click outside the dropdown element.</p>
<h3 id="heading-dropdown-keyboard-interaction">Dropdown Keyboard Interaction</h3>
<p>Pressing the <code>UP</code> or <code>DOWN</code> arrow keys should open the dropdown. When the dropdown is open, these keys should allow navigation through the options, moving the selection up or down. Also, clicking on an option or pressing the <code>Space</code> or <code>Enter</code> keys while an option is focused should update the button's displayed value. This behavior aims to replicate the interaction of a standard select element.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> elements = {
  <span class="hljs-attr">button</span>: <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'[role="combobox"]'</span>),
  <span class="hljs-attr">dropdown</span>: <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'[role="listbox"]'</span>),
  <span class="hljs-attr">options</span>: <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">'[role="option"]'</span>), <span class="hljs-comment">// add the options elements</span>
};
<span class="hljs-keyword">let</span> isDropdownOpen = <span class="hljs-literal">false</span>;
<span class="hljs-keyword">let</span> currentOptionIndex = <span class="hljs-number">0</span>;

<span class="hljs-keyword">const</span> toggleDropdown = <span class="hljs-function">() =&gt;</span> {
  elements.dropdown.classList.toggle(<span class="hljs-string">'active'</span>);
  isDropdownOpen = !isDropdownOpen;
  elements.button.setAttribute(<span class="hljs-string">'aria-expanded'</span>, isDropdownOpen.toString());

  <span class="hljs-keyword">if</span> (isDropdownOpen) {
    focusCurrentOption();
  } <span class="hljs-keyword">else</span> {
    elements.button.focus(); <span class="hljs-comment">// focus the button when the dropdown is closed just like the select element</span>
  }
};

<span class="hljs-keyword">const</span> focusCurrentOption = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> currentOption = elements.options[currentOptionIndex];

  currentOption.classList.add(<span class="hljs-string">'current'</span>);
  currentOption.focus();

  elements.options.forEach(<span class="hljs-function">(<span class="hljs-params">option, index</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (option !== currentOption) {
      option.classList.remove(<span class="hljs-string">'current'</span>);
    }
  });
};

<span class="hljs-keyword">const</span> handleKeyPress = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.preventDefault();
  <span class="hljs-keyword">const</span> { key } = event;
  <span class="hljs-keyword">const</span> openKeys = [<span class="hljs-string">'ArrowDown'</span>, <span class="hljs-string">'ArrowUp'</span>, <span class="hljs-string">'Enter'</span>, <span class="hljs-string">' '</span>];

  <span class="hljs-keyword">if</span> (!isDropdownOpen &amp;&amp; openKeys.includes(key)) {
    toggleDropdown();

  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (isDropdownOpen) {
    <span class="hljs-keyword">switch</span> (key) {
      <span class="hljs-keyword">case</span> <span class="hljs-string">'Escape'</span>:
        toggleDropdown();
        <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">case</span> <span class="hljs-string">'ArrowDown'</span>:
        moveFocusDown();
        <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">case</span> <span class="hljs-string">'ArrowUp'</span>:
        moveFocusUp();
        <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">case</span> <span class="hljs-string">'Enter'</span>:
      <span class="hljs-keyword">case</span> <span class="hljs-string">' '</span>:
        selectCurrentOption();
        <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">default</span>:
        <span class="hljs-keyword">break</span>;
    }
  }
};

<span class="hljs-keyword">const</span> handleDocumentInteraction = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> isClickInsideButton = elements.button.contains(event.target);
  <span class="hljs-keyword">const</span> isClickInsideDropdown = elements.dropdown.contains(event.target);

  <span class="hljs-keyword">if</span> (isClickInsideButton || (!isClickInsideDropdown &amp;&amp; isDropdownOpen)) {
    toggleDropdown();
  }

  <span class="hljs-comment">// Check if the click is on an option</span>
  <span class="hljs-keyword">const</span> clickedOption = event.target.closest(<span class="hljs-string">'[role="option"]'</span>);
  <span class="hljs-keyword">if</span> (clickedOption) {
    selectOptionByElement(clickedOption);
  }
};


<span class="hljs-keyword">const</span> moveFocusDown = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">if</span> (currentOptionIndex &lt; elements.options.length - <span class="hljs-number">1</span>) {
    currentOptionIndex++;
  } <span class="hljs-keyword">else</span> {
    currentOptionIndex = <span class="hljs-number">0</span>;
  }
  focusCurrentOption();
};

<span class="hljs-keyword">const</span> moveFocusUp = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">if</span> (currentOptionIndex &gt; <span class="hljs-number">0</span>) {
    currentOptionIndex--;
  } <span class="hljs-keyword">else</span> {
    currentOptionIndex = elements.options.length - <span class="hljs-number">1</span>;
  }
  focusCurrentOption();
};

<span class="hljs-keyword">const</span> selectCurrentOption = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> selectedOption = elements.options[currentOptionIndex];
  selectOptionByElement(selectedOption);
};

<span class="hljs-keyword">const</span> selectOptionByElement = <span class="hljs-function">(<span class="hljs-params">optionElement</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> optionValue = optionElement.textContent;

  elements.button.textContent = optionValue;
  elements.options.forEach(<span class="hljs-function"><span class="hljs-params">option</span> =&gt;</span> {
    option.classList.remove(<span class="hljs-string">'active'</span>);
    option.setAttribute(<span class="hljs-string">'aria-selected'</span>, <span class="hljs-string">'false'</span>);
  });

  optionElement.classList.add(<span class="hljs-string">'active'</span>);
  optionElement.setAttribute(<span class="hljs-string">'aria-selected'</span>, <span class="hljs-string">'true'</span>);
};

elements.button.addEventListener(<span class="hljs-string">'keydown'</span>, handleKeyPress);
<span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">'click'</span>, handleDocumentInteraction);
</code></pre>
<p>In the updated code, we've added keyboard navigation and option selection. Here's the breakdown:</p>
<ol>
<li>The <code>elements</code> object now includes a reference to the option elements with the role "option."</li>
<li>The dropdown can also be opened with keys like <code>ArrowDown</code>, <code>ArrowUp</code>, <code>Space</code> or <code>Enter</code></li>
<li>When the dropdown is open, <code>Escape</code> closes the dropdown, <code>ArrowDown</code> moves focus down the options, <code>ArrowUp</code> moves it up, and <code>Enter</code> or <code>Space</code> selects the current option.</li>
<li>Clicking an option or using keyboard input selects the option.</li>
<li>The selected option is displayed in the button, and the aria-selected state of the option is updated.</li>
<li><code>active</code> class is now added to the selected option</li>
</ol>
<h3 id="heading-fixing-option-visibility-issue">Fixing Option Visibility Issue</h3>
<p>This looks good so far – but if you're following along and you test this code, you'll notice an issue: if an option is out of view and the down arrow is pressed the option isn't shown. </p>
<p>To fix this, you can use the <code>scrollIntoView</code> method to ensure that the current option is scrolled into view when it is focused. Add it to the <code>focusCurrentOption</code> like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> focusCurrentOption = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> currentOption = elements.options[currentOptionIndex];

  currentOption.classList.add(<span class="hljs-string">'current'</span>);
  currentOption.focus();

  <span class="hljs-comment">// Scroll the current option into view</span>
  currentOption.scrollIntoView({
    <span class="hljs-attr">block</span>: <span class="hljs-string">'nearest'</span>,
  });

  elements.options.forEach(<span class="hljs-function">(<span class="hljs-params">option, index</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (option !== currentOption) {
      option.classList.remove(<span class="hljs-string">'current'</span>);
    }
  });
};

<span class="hljs-comment">// rest of code</span>
</code></pre>
<p>Also when the user selects an option, the dropdown should close, the same way the select element works. Call the <code>toggleDropdown</code> function in the <code>selectOptionByElement</code> function like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> selectOptionByElement = <span class="hljs-function">(<span class="hljs-params">optionElement</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> optionValue = optionElement.textContent;

  elements.button.textContent = optionValue;
  elements.options.forEach(<span class="hljs-function"><span class="hljs-params">option</span> =&gt;</span> {
    option.classList.remove(<span class="hljs-string">'active'</span>);
    option.setAttribute(<span class="hljs-string">'aria-selected'</span>, <span class="hljs-string">'false'</span>);
  });

  optionElement.classList.add(<span class="hljs-string">'active'</span>);
  optionElement.setAttribute(<span class="hljs-string">'aria-selected'</span>, <span class="hljs-string">'true'</span>);

  toggleDropdown(); <span class="hljs-comment">// close the dropdown once an option is selected</span>

};
</code></pre>
<h3 id="heading-highlighting-options-on-alphanumeric-key-press">Highlighting Options on Alphanumeric Key Press</h3>
<p>Pressing an alphanumeric keys should highlight the option that starts with said character. And if the same character is pressed again then the next option should be highlighted and so on.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> lastTypedChar = <span class="hljs-string">''</span>;
<span class="hljs-keyword">let</span> lastMatchingIndex = <span class="hljs-number">0</span>;

<span class="hljs-comment">// update the handleKeyPress function</span>

<span class="hljs-keyword">const</span> handleKeyPress = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.preventDefault();
  <span class="hljs-keyword">const</span> { key } = event;
  <span class="hljs-keyword">const</span> openKeys = [<span class="hljs-string">'ArrowDown'</span>, <span class="hljs-string">'ArrowUp'</span>, <span class="hljs-string">'Enter'</span>, <span class="hljs-string">' '</span>];

  <span class="hljs-keyword">if</span> (!isDropdownOpen &amp;&amp; openKeys.includes(key)) {
    toggleDropdown();

  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (isDropdownOpen) {
    <span class="hljs-keyword">switch</span> (key) {
      <span class="hljs-keyword">case</span> <span class="hljs-string">'Escape'</span>:
        toggleDropdown();
        <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">case</span> <span class="hljs-string">'ArrowDown'</span>:
        moveFocusDown();
        <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">case</span> <span class="hljs-string">'ArrowUp'</span>:
        moveFocusUp();
        <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">case</span> <span class="hljs-string">'Enter'</span>:
      <span class="hljs-keyword">case</span> <span class="hljs-string">' '</span>:
        selectCurrentOption();
        <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">default</span>:
        <span class="hljs-comment">// Handle alphanumeric key presses for mini-search</span>
        handleAlphanumericKeyPress(key);
        <span class="hljs-keyword">break</span>;
    }
  }
};


<span class="hljs-comment">// previous code</span>

<span class="hljs-keyword">const</span> handleAlphanumericKeyPress = <span class="hljs-function">(<span class="hljs-params">key</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> typedChar = key.toLowerCase();

  <span class="hljs-keyword">if</span> (lastTypedChar !== typedChar) {
    lastMatchingIndex = <span class="hljs-number">0</span>;
  }

  <span class="hljs-keyword">const</span> matchingOptions = <span class="hljs-built_in">Array</span>.from(elements.options).filter(<span class="hljs-function">(<span class="hljs-params">option</span>) =&gt;</span>
    option.textContent.toLowerCase().startsWith(typedChar)
  );

  <span class="hljs-keyword">if</span> (matchingOptions.length) {
    <span class="hljs-keyword">if</span> (lastMatchingIndex === matchingOptions.length) {
      lastMatchingIndex = <span class="hljs-number">0</span>;
    }
    <span class="hljs-keyword">let</span> value = matchingOptions[lastMatchingIndex]
    <span class="hljs-keyword">const</span> index = <span class="hljs-built_in">Array</span>.from(elements.options).indexOf(value);
    currentOptionIndex = index;
    focusCurrentOption();
    lastMatchingIndex += <span class="hljs-number">1</span>;
  }
  lastTypedChar = typedChar;
};

<span class="hljs-comment">// rest of the code</span>
</code></pre>
<p>Running the code and testing it with both mouse and keyboard inputs should result in the expected behavior. </p>
<h3 id="heading-enhancing-screen-reader-functionality">Enhancing Screen Reader Functionality</h3>
<p>The last functionality I'm addressing in this article is the screen reader functionality.</p>
<p>For screen reader users, selecting an option should announce the selected option, Just like the default HTML select element. Update the HTML to have a div that will contain the content to be announced, like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"select"</span>&gt;</span>Custom Select box<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
     <span class="hljs-attr">role</span>=<span class="hljs-string">"combobox"</span>
     <span class="hljs-attr">id</span>=<span class="hljs-string">"select"</span>
     <span class="hljs-attr">value</span>=<span class="hljs-string">"Select"</span>
     <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"listbox"</span>
     <span class="hljs-attr">aria-haspopup</span>=<span class="hljs-string">"listbox"</span>
     <span class="hljs-attr">tabindex</span>=<span class="hljs-string">"0"</span>
     <span class="hljs-attr">aria-expanded</span>=<span class="hljs-string">"false"</span>&gt;</span>
    Select<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"announcement"</span> <span class="hljs-attr">aria-live</span>=<span class="hljs-string">"assertive"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"opacity:0;"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-comment">&lt;!-- The screen reader will announce the content in this element  --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"listbox"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"listbox"</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"option"</span>&gt;</span>Option 1<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"option"</span>&gt;</span>Option 2<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"option"</span>&gt;</span>Option 3<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>Then use JavaScript to update the value in the alert:</p>
<pre><code class="lang-js"><span class="hljs-comment">// previous code</span>
<span class="hljs-keyword">const</span> selectOptionByElement = <span class="hljs-function">(<span class="hljs-params">optionElement</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> optionValue = optionElement.textContent;

  elements.button.textContent = optionValue;
  elements.options.forEach(<span class="hljs-function"><span class="hljs-params">option</span> =&gt;</span> {
    option.classList.remove(<span class="hljs-string">'active'</span>);
    option.setAttribute(<span class="hljs-string">'aria-selected'</span>, <span class="hljs-string">'false'</span>);
  });

  optionElement.classList.add(<span class="hljs-string">'active'</span>);
  optionElement.setAttribute(<span class="hljs-string">'aria-selected'</span>, <span class="hljs-string">'true'</span>);

  toggleDropdown();
  announceOption(optionValue); <span class="hljs-comment">// Announce the selected option</span>
};

<span class="hljs-keyword">const</span> announceOption = <span class="hljs-function">(<span class="hljs-params">text</span>) =&gt;</span> {
  elements.announcement.textContent = text;
  elements.announcement.setAttribute(<span class="hljs-string">'aria-live'</span>, <span class="hljs-string">'assertive'</span>);
  <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
    elements.announcement.textContent = <span class="hljs-string">''</span>;
    elements.announcement.setAttribute(<span class="hljs-string">'aria-live'</span>, <span class="hljs-string">'off'</span>);
  }, <span class="hljs-number">1000</span>); <span class="hljs-comment">// Announce and clear after 1 second (adjust as needed)</span>
};

<span class="hljs-comment">// rest of code</span>
</code></pre>
<p>In the code above, I've added an <code>announceOption</code> function. The function is called whenever a user selects an option. The use of the <em>assertive</em> value in the <code>aria-live</code> attribute signals to the screen reader to interrupt its current announcement and promptly announce the updated value.</p>
<p>Now when you test this with a screenreader, the screen reader announces the selected option as expected.</p>
<p>Here's a working example of the custom select on <a target="_blank" href="https://codepen.io/leezee/pen/abXPjvM">Codepen</a>:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/leezee/embed/abXPjvM" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>There's room for improvement in these features, such as adding multiple select options, autocomplete, and enhancing the overall look. Yet, my intention is for this article to be a helpful guide, encouraging you to keep accessibility in mind when building a component.</p>
<p>If you're looking for a package to use you should consider using <a target="_blank" href="https://react-select.com/home">React-Select</a>  or <a target="_blank" href="https://www.npmjs.com/package/vue3-select">Vue3-select</a>.</p>
<p>Thank you so much for reading this article, if you found it helpful consider sharing. Happy coding!</p>
<p>You can connect with me on <a target="_blank" href="https://www.linkedin.com/in/elizabeth-meshioye/">Linkedin</a> or <a target="_blank" href="https://github.com/Lezette">Github</a></p>
<h3 id="heading-resources-used-in-this-article">Resources used in this article:</h3>
<ul>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/combobox_role">MDN Combobox roles</a></li>
<li><a target="_blank" href="https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/#accessiblenameguidancebyrole">W3 ARIA practices</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
