<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Kedar Kulkarni</title>
    <description>The latest articles on Forem by Kedar Kulkarni (@kedar7).</description>
    <link>https://forem.com/kedar7</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F487161%2F59d564da-424f-4500-836d-834e523ea491.jpeg</url>
      <title>Forem: Kedar Kulkarni</title>
      <link>https://forem.com/kedar7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kedar7"/>
    <language>en</language>
    <item>
      <title>Stop Burning Money: How Smarter Angular Code Slashes Your Server Bills</title>
      <dc:creator>Kedar Kulkarni</dc:creator>
      <pubDate>Tue, 27 Jan 2026 16:08:46 +0000</pubDate>
      <link>https://forem.com/kedar7/stop-burning-money-how-smarter-angular-code-slashes-your-server-bills-1la2</link>
      <guid>https://forem.com/kedar7/stop-burning-money-how-smarter-angular-code-slashes-your-server-bills-1la2</guid>
      <description>&lt;p&gt;Most developers think "server costs" are a backend problem. But the truth is, your &lt;strong&gt;Frontend&lt;/strong&gt; is the remote control for your cloud invoice. If your frontend is "dumb," it forces your server to work overtime.&lt;/p&gt;

&lt;p&gt;For companies scaling to millions of users, "lazy" frontend habits can result in server bills that are &lt;strong&gt;5x to 10x higher&lt;/strong&gt; than they need to be. Here is how optimizing your Angular app can save you thousands of dollars, explained in plain English.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Stop Paying for "Waiters" (Static Hosting)
&lt;/h3&gt;

&lt;p&gt;Imagine hiring a waiter to stand by a table 24/7, even when no one is there. That’s what it's like when you serve Angular through a Node.js or Java server.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Fix:&lt;/strong&gt; Build your app as "Static Files" (&lt;code&gt;ng build&lt;/code&gt;) and host them on &lt;strong&gt;S3 + CloudFront&lt;/strong&gt;, &lt;strong&gt;Vercel&lt;/strong&gt;, or &lt;strong&gt;Netlify&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it saves money:&lt;/strong&gt; A virtual server (like EC2) costs roughly &lt;strong&gt;₹2,500/mo&lt;/strong&gt; just to stay "on." Static hosting costs about &lt;strong&gt;₹50/mo&lt;/strong&gt; because you only pay for storage and actual traffic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro Tip:&lt;/strong&gt; If you don't need SEO-heavy pages, avoid SSR (Server Side Rendering). Every SSR request burns server CPU/RAM; Static files burn nothing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. The "Ask Once" Rule (API Caching)
&lt;/h3&gt;

&lt;p&gt;If you need a list of users for five different parts of a page, don't ask the server five times. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Fix:&lt;/strong&gt; Use the RxJS &lt;code&gt;shareReplay(1)&lt;/code&gt; operator in your services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it saves money:&lt;/strong&gt; Every API hit burns backend compute. Multicasting your data can reduce your backend requests by &lt;strong&gt;60–80%&lt;/strong&gt;, allowing you to serve more users without upgrading your server.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Don't Be a "Stuttering" Search (Debouncing)
&lt;/h3&gt;

&lt;p&gt;If a user types "iPhone" in a search bar, a bad app sends 6 separate requests to your database (&lt;code&gt;i&lt;/code&gt;, &lt;code&gt;iP&lt;/code&gt;, &lt;code&gt;iPh&lt;/code&gt;...).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Fix:&lt;/strong&gt; Use &lt;code&gt;debounceTime(400)&lt;/code&gt;. Wait for the user to stop typing before hitting the API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it saves money:&lt;/strong&gt; It reduces Database load by up to &lt;strong&gt;90%&lt;/strong&gt;. This keeps you on a "Basic" database plan instead of forced upgrades to "Enterprise" IOPS tiers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Smart Loading (Lazy Loading &amp;amp; &lt;a class="mentioned-user" href="https://dev.to/defer"&gt;@defer&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Why load the "Admin Dashboard" code for a customer who just wants to see their landing page? &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Fix:&lt;/strong&gt; Use &lt;code&gt;loadChildren&lt;/code&gt; for routes and the new &lt;strong&gt;&lt;code&gt;@defer&lt;/code&gt; blocks&lt;/strong&gt; for template-level lazy loading.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it saves money:&lt;/strong&gt; Cloud providers charge for "Egress" (data sent out). Smaller bundles = lower bandwidth fees.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. The "Offline Store" Strategy (PWA)
&lt;/h3&gt;

&lt;p&gt;In a standard app, every refresh re-downloads the same logos, fonts, and core files. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Fix:&lt;/strong&gt; Run &lt;code&gt;ng add @angular/pwa&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it saves money:&lt;/strong&gt; Service Workers store your app shell on the user's device. For a large app, this saves &lt;strong&gt;40–60% on bandwidth&lt;/strong&gt; because the user's device "hosts" the heavy UI files locally.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. "Micro-Surgery" for Large Apps (Micro-Frontends)
&lt;/h3&gt;

&lt;p&gt;In giant enterprise apps, a 1-line change often requires re-building and re-deploying a 20MB application. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Fix:&lt;/strong&gt; Use &lt;strong&gt;Module Federation&lt;/strong&gt; to break the app into independent Micro-Frontends (MFE).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it saves money:&lt;/strong&gt; You only run CI/CD builds for the specific module that changed. This slashes your "Build Minute" costs on platforms like GitHub Actions or CircleCI.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  7. Signals: The "Energy Efficient" Lightbulb
&lt;/h3&gt;

&lt;p&gt;Standard Angular checks your &lt;em&gt;entire&lt;/em&gt; app tree for changes every time you click. &lt;strong&gt;Signals&lt;/strong&gt; only update the exact spot that changed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Fix:&lt;/strong&gt; Migrate from traditional variables to &lt;strong&gt;Angular Signals&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it saves money:&lt;/strong&gt; Lower CPU usage. In professional VDI or "Cloud Desktop" environments, this reduces the infrastructure footprint needed to host users.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  💰 The Financial Impact: At a Glance
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;User Base&lt;/th&gt;
&lt;th&gt;"Dumb" Angular Bill&lt;/th&gt;
&lt;th&gt;"Smart" Angular Bill&lt;/th&gt;
&lt;th&gt;Savings&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Small (1k users)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;₹5,000 / mo&lt;/td&gt;
&lt;td&gt;₹200 / mo&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;96%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Medium (50k users)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;₹50,000 / mo&lt;/td&gt;
&lt;td&gt;₹8,000 / mo&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;84%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Enterprise (1M+)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;₹5,00,000+ / mo&lt;/td&gt;
&lt;td&gt;₹1,00,000 / mo&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;₹4 Lakhs/mo&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  The Bottom Line
&lt;/h3&gt;

&lt;p&gt;A "cheap" server bill starts with high-quality code. By making your Angular app smarter, you stop treating your backend like a 24/7 punching bag. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s your favorite way to save on cloud costs? Let's discuss in the comments! 👇&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>performance</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Complete Guide to ADA Compliance in Angular Applications</title>
      <dc:creator>Kedar Kulkarni</dc:creator>
      <pubDate>Sat, 12 Jul 2025 04:07:39 +0000</pubDate>
      <link>https://forem.com/kedar7/complete-guide-to-ada-compliance-in-angular-applications-8b4</link>
      <guid>https://forem.com/kedar7/complete-guide-to-ada-compliance-in-angular-applications-8b4</guid>
      <description>&lt;p&gt;In today’s digital-first world, accessibility is no longer optional—it’s essential. Whether you're building a sleek startup UI or a government web app, your Angular project must cater to everyone, including people with disabilities. This blog is your one-stop guide to achieving &lt;strong&gt;ADA compliance in Angular&lt;/strong&gt;—from strategy to implementation.&lt;/p&gt;




&lt;h3&gt;
  
  
  🚀 Why Accessibility Matters in Angular
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Americans with Disabilities Act (ADA)&lt;/strong&gt; mandates digital accessibility as part of equal access. Accessibility ensures that users with visual, auditory, cognitive, or motor impairments can effectively use your application.&lt;/p&gt;

&lt;p&gt;Angular, as a dynamic Single Page Application (SPA) framework, adds complexity—rendering content client-side, which can break assistive technologies like screen readers.&lt;/p&gt;

&lt;p&gt;If you're developing with Angular, &lt;strong&gt;this guide will help you:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand what ADA compliance means&lt;/li&gt;
&lt;li&gt;Identify accessibility issues in Angular SPAs&lt;/li&gt;
&lt;li&gt;Fix common UI problems using real-world practices&lt;/li&gt;
&lt;li&gt;Test and maintain accessible code at scale&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📚 Understanding ADA, WCAG, and Angular
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🌐 What is ADA Compliance?
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;ADA&lt;/strong&gt; prohibits discrimination against individuals with disabilities in public spaces—this now includes &lt;strong&gt;web applications&lt;/strong&gt;. This is enforced through adherence to &lt;strong&gt;WCAG (Web Content Accessibility Guidelines)&lt;/strong&gt;, which defines standards like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Perceivable&lt;/strong&gt;: Content must be available to the senses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operable&lt;/strong&gt;: Users can interact with it using keyboards and assistive tech&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understandable&lt;/strong&gt;: Content and UI are easy to follow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robust&lt;/strong&gt;: Compatible with future tools and tech&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧠 How Angular Fits Into Accessibility
&lt;/h2&gt;

&lt;p&gt;Angular’s SPA behavior means content changes without full page reloads. While great for performance, this can trip up screen readers and keyboard users.&lt;/p&gt;

&lt;p&gt;Key Angular challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Missing focus management during route changes&lt;/li&gt;
&lt;li&gt;Improper or missing ARIA roles&lt;/li&gt;
&lt;li&gt;Custom components with no keyboard support&lt;/li&gt;
&lt;li&gt;Dynamic updates that are not announced&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fortunately, Angular has tools like &lt;strong&gt;Angular CDK’s a11y package&lt;/strong&gt; and &lt;strong&gt;Angular Material&lt;/strong&gt;, which include built-in accessibility support.&lt;/p&gt;




&lt;h2&gt;
  
  
  🕵️‍♂️ Identifying Accessibility Issues in Angular Apps
&lt;/h2&gt;

&lt;p&gt;Here’s how to evaluate your app’s accessibility status:&lt;/p&gt;

&lt;h3&gt;
  
  
  🔧 Automated Tools
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;axe-core&lt;/strong&gt; (browser extension / CLI)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Lighthouse&lt;/strong&gt; (built into Chrome DevTools)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WAVE Tool&lt;/strong&gt; (web-based or extension)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pa11y&lt;/strong&gt; (perfect for CI/CD)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  👀 Manual Testing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use screen readers (VoiceOver, NVDA, JAWS)&lt;/li&gt;
&lt;li&gt;Navigate with only a keyboard (Tab, Enter, Arrow keys)&lt;/li&gt;
&lt;li&gt;Use high-contrast mode&lt;/li&gt;
&lt;li&gt;Zoom in to 200% and verify layout&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔥 Common Angular Accessibility Pitfalls
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Focus Management Failures&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;After route transitions, users using screen readers may get lost. Fix it using a service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FocusManager&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;focusMainHeading&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Call this after navigation.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. &lt;strong&gt;Dynamic Content Not Announced&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;aria-live&lt;/code&gt; regions to inform screen readers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;aria-live=&lt;/span&gt;&lt;span class="s"&gt;"polite"&lt;/span&gt; &lt;span class="na"&gt;aria-atomic=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sr-only"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  {{ statusMessage }}
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. &lt;strong&gt;Custom Components Missing Labels&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;✅ Use &lt;code&gt;aria-label&lt;/code&gt; or &lt;code&gt;aria-labelledby&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Search query"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"name-label"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Name&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;aria-labelledby=&lt;/span&gt;&lt;span class="s"&gt;"name-label"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  4. &lt;strong&gt;Missing Keyboard Support&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Ensure buttons, toggles, and modals can be accessed via Tab and activated via Enter/Space:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;HostListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keydown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nf"&gt;onKeyDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;KeyboardEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. &lt;strong&gt;Color Contrast Issues&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;WCAG requires a contrast ratio of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;4.5:1&lt;/strong&gt; for normal text&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3:1&lt;/strong&gt; for large text&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use &lt;a href="https://webaim.org/resources/contrastchecker/" rel="noopener noreferrer"&gt;WebAIM contrast checker&lt;/a&gt; to validate your theme.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧰 Tools &amp;amp; Libraries for Angular Accessibility
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Angular CDK a11y&lt;/strong&gt;: Focus trapping, live announcers, overlays&lt;/li&gt;
&lt;li&gt;🎨 &lt;strong&gt;Angular Material&lt;/strong&gt;: Accessible components (but still test them!)&lt;/li&gt;
&lt;li&gt;🛠️ &lt;strong&gt;Codelyzer + TSLint&lt;/strong&gt;: Add accessibility rules&lt;/li&gt;
&lt;li&gt;🧪 &lt;strong&gt;axe-core Angular Integration&lt;/strong&gt;: Run a11y tests programmatically&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧪 Real Angular Accessibility Failures (Case Studies)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔎 Case 1: E-Commerce Filter Inaccessibility
&lt;/h3&gt;

&lt;p&gt;Problem: Custom checkboxes with no ARIA roles&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix: Added semantic markup + live region updates
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔎 Case 2: Government Services Portal
&lt;/h3&gt;

&lt;p&gt;Problem: Incomplete forms using keyboard, missing skip links&lt;br&gt;
Fix: Added semantic HTML + skip navigation + ARIA&lt;br&gt;
📄 Result: Passed WCAG 2.1 AA audit&lt;/p&gt;


&lt;h3&gt;
  
  
  🔎 Case 3: Online Learning Platform Lawsuit
&lt;/h3&gt;

&lt;p&gt;Problem: No captions, no labels, no keyboard escape&lt;br&gt;
Fix: Full remediation with CI-integrated a11y tests&lt;br&gt;
✅ Result: Legal risk mitigated + better UX&lt;/p&gt;


&lt;h2&gt;
  
  
  🧑‍💻 Accessibility Best Practices in Angular
&lt;/h2&gt;
&lt;h3&gt;
  
  
  💡 Design Phase
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create personas that include users with disabilities&lt;/li&gt;
&lt;li&gt;Use accessible color palettes from the start&lt;/li&gt;
&lt;li&gt;Test wireframes with keyboard and screen reader users&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  🛠️ Development Phase
&lt;/h3&gt;
&lt;h4&gt;
  
  
  ✅ Semantic HTML First
&lt;/h4&gt;

&lt;p&gt;Use &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; instead of &lt;code&gt;div&lt;/code&gt;s.&lt;/p&gt;
&lt;h4&gt;
  
  
  ✅ ARIA Attributes
&lt;/h4&gt;

&lt;p&gt;Use only when HTML can’t express behavior. Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt;
  &lt;span class="na"&gt;[attr.aria-label]=&lt;/span&gt;&lt;span class="s"&gt;"isOpen ? 'Collapse menu' : 'Expand menu'"&lt;/span&gt;
  &lt;span class="na"&gt;[attr.aria-expanded]=&lt;/span&gt;&lt;span class="s"&gt;"isOpen"&lt;/span&gt;
  &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"toggleMenu()"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Menu
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ✅ Keyboard Navigation
&lt;/h4&gt;

&lt;p&gt;All interactive components should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Be focusable (&lt;code&gt;tabindex="0"&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Respond to &lt;code&gt;Enter&lt;/code&gt; or &lt;code&gt;Space&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Maintain logical tab order&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🧪 Testing &amp;amp; Maintenance
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;axe-core&lt;/code&gt; or &lt;code&gt;pa11y&lt;/code&gt; after each deploy&lt;/li&gt;
&lt;li&gt;Include &lt;code&gt;test:a11y&lt;/code&gt; in your package.json:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test:a11y"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ng test &amp;amp;&amp;amp; pa11y http://localhost:4200"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lint:a11y"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ng lint --fix"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Train your dev team to use screen readers&lt;/li&gt;
&lt;li&gt;Document accessibility rules in your internal UI guidelines&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🏁 Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ADA compliance in Angular is not just about checking boxes—it’s about building web apps that welcome everyone.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With Angular’s tools, WCAG guidance, and proactive testing, you can ship products that are usable, ethical, and inclusive.&lt;/p&gt;

&lt;p&gt;🌎 Accessibility is a journey, not a one-time fix. Start today, improve continuously.&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/WAI/WCAG21/quickref/" rel="noopener noreferrer"&gt;WCAG 2.1 Quick Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://angular.io/guide/accessibility" rel="noopener noreferrer"&gt;Angular Accessibility Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://material.angular.io/cdk/a11y/overview" rel="noopener noreferrer"&gt;Angular CDK a11y&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dequelabs/axe-core-npm/tree/develop/packages/angular" rel="noopener noreferrer"&gt;axe-core for Angular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://webaim.org/articles/screenreader_testing/" rel="noopener noreferrer"&gt;Screen Reader Testing - WebAIM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve developed a custom ADA-compliant Angular documentation site - &lt;a href="https://ada-compliance.vercel.app/" rel="noopener noreferrer"&gt;https://ada-compliance.vercel.app/&lt;/a&gt;, feel free to explore it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>html</category>
      <category>a11y</category>
      <category>frontend</category>
    </item>
    <item>
      <title>⚙️ ARIA for Developers – Roles, States, and Accessible Components in React</title>
      <dc:creator>Kedar Kulkarni</dc:creator>
      <pubDate>Sat, 12 Jul 2025 04:05:08 +0000</pubDate>
      <link>https://forem.com/kedar7/aria-for-developers-roles-states-and-accessible-components-in-react-14p8</link>
      <guid>https://forem.com/kedar7/aria-for-developers-roles-states-and-accessible-components-in-react-14p8</guid>
      <description>&lt;p&gt;In the first two parts of this series, we covered the fundamentals of accessibility and how to fix common issues like missing labels, bad contrast, and incorrect heading structure. Now, let’s dive deeper into &lt;strong&gt;ARIA (Accessible Rich Internet Applications)&lt;/strong&gt; and how to use it with &lt;strong&gt;React&lt;/strong&gt; to build dynamic and accessible web interfaces.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔎 What Is ARIA?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;WAI-ARIA&lt;/strong&gt; is a W3C specification designed to enhance the accessibility of custom web components and dynamic content. When native HTML elements fall short—like custom dropdowns, modals, sliders, or toggles—&lt;strong&gt;ARIA roles and attributes&lt;/strong&gt; bridge the gap by communicating additional semantics to assistive technologies.&lt;/p&gt;




&lt;h3&gt;
  
  
  ⚠️ Before You Use ARIA…
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;🧠 “If you can use a native HTML element with the built-in behavior you need—&lt;strong&gt;use that instead of ARIA&lt;/strong&gt;.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Native elements like &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; already have accessibility features. Only use ARIA if there's &lt;strong&gt;no semantic HTML alternative&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔧 ARIA Core Concepts
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Role&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Defines what the element is (e.g., &lt;code&gt;button&lt;/code&gt;, &lt;code&gt;dialog&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Describes current conditions (e.g., &lt;code&gt;aria-expanded="true"&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Property&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Provides extra context (e.g., &lt;code&gt;aria-labelledby="title"&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Let’s see how to apply these in a real-world project using &lt;strong&gt;React&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧪 React + ARIA: Practical Examples
&lt;/h2&gt;




&lt;h3&gt;
  
  
  1️⃣ Toggle Button (Accessible Switch)
&lt;/h3&gt;

&lt;p&gt;Here’s how to create a &lt;strong&gt;keyboard-operable toggle switch&lt;/strong&gt; using ARIA.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ToggleButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isOn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsOn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
      &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"switch"&lt;/span&gt;
      &lt;span class="na"&gt;aria-checked&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isOn&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;tabIndex&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setIsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isOn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onKeyDown&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="nf"&gt;setIsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isOn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inline-block&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10px 20px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isOn&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#4caf50&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#ccc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;20px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pointer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;userSelect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isOn&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ON&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OFF&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🧠 ARIA Highlights:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;role="switch"&lt;/code&gt; tells screen readers it’s a toggle.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aria-checked&lt;/code&gt; indicates current state.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tabIndex={0}&lt;/code&gt; makes the element focusable.&lt;/li&gt;
&lt;li&gt;Arrow keys or spacebar trigger the toggle.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2️⃣ Custom Dropdown with Keyboard Support
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Apple&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Banana&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cherry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Dropdown&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsOpen&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelected&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;highlightedIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setHighlightedIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dropdownRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;dropdownRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;dropdownRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleKeyDown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="nf"&gt;setIsOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ArrowDown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="nf"&gt;setHighlightedIndex&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ArrowUp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="nf"&gt;setHighlightedIndex&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="nf"&gt;setSelected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;highlightedIndex&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
          &lt;span class="nf"&gt;setIsOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Escape&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="nf"&gt;setIsOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;break&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
        &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
        &lt;span class="na"&gt;aria-haspopup&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"listbox"&lt;/span&gt;
        &lt;span class="na"&gt;aria-expanded&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;aria-controls&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-list"&lt;/span&gt;
        &lt;span class="na"&gt;tabIndex&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setIsOpen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onKeyDown&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleKeyDown&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#eee&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1px solid #ccc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;200px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pointer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Select an option&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;
          &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-list"&lt;/span&gt;
          &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"listbox"&lt;/span&gt;
          &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dropdownRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;tabIndex&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;listStyle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1px solid #ccc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;
              &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;opt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"option"&lt;/span&gt;
              &lt;span class="na"&gt;aria-selected&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;highlightedIndex&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;setSelected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;setIsOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;highlightedIndex&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#007bff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;highlightedIndex&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;black&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;opt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ARIA Usage:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;role="button"&lt;/code&gt;: Declares the trigger element&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aria-expanded&lt;/code&gt;: Shows whether dropdown is open&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aria-haspopup="listbox"&lt;/code&gt;: Identifies a related popup&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;role="listbox"&lt;/code&gt; &amp;amp; &lt;code&gt;role="option"&lt;/code&gt;: Define the dropdown structure&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3️⃣ Accessible Labeling: &lt;code&gt;aria-label&lt;/code&gt; &amp;amp; &lt;code&gt;aria-labelledby&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Sometimes visible labels aren’t possible. ARIA attributes help provide accessible names.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;aria-label&lt;/code&gt; (Custom label directly on the element):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"First name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;aria-labelledby&lt;/code&gt; (Reference another element's &lt;code&gt;id&lt;/code&gt;):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"label1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Username&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;aria-labelledby=&lt;/span&gt;&lt;span class="s"&gt;"label1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔒 ARIA Do’s and Don’ts
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;✅ Do This&lt;/th&gt;
&lt;th&gt;❌ Don’t Do This&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Use semantic HTML if available&lt;/td&gt;
&lt;td&gt;Replace native elements with divs + ARIA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Make ARIA widgets keyboard-accessible&lt;/td&gt;
&lt;td&gt;Ignore focus/keyboard behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test with screen readers &amp;amp; WAVE&lt;/td&gt;
&lt;td&gt;Assume ARIA works out-of-the-box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use &lt;code&gt;aria-hidden="true"&lt;/code&gt; sparingly&lt;/td&gt;
&lt;td&gt;Apply it to interactive or focusable elements&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  🧠 Key ARIA Roles You Should Know
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;button&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Interactive element&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dialog&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modal popup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;tab&lt;/code&gt;, &lt;code&gt;tabpanel&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Tab interfaces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;listbox&lt;/code&gt; / &lt;code&gt;option&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Dropdowns or selections&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;alert&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Announce important changes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🧩 Full list: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles" rel="noopener noreferrer"&gt;ARIA Roles Overview – MDN&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  📋 Summary: Building Accessible Components with ARIA
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Topic&lt;/th&gt;
&lt;th&gt;Key Point&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Use ARIA selectively&lt;/td&gt;
&lt;td&gt;Prefer native elements when possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Labeling matters&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;aria-label&lt;/code&gt; or &lt;code&gt;aria-labelledby&lt;/code&gt; to name elements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manage state&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;aria-expanded&lt;/code&gt;, &lt;code&gt;aria-checked&lt;/code&gt;, etc. to reflect status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Support keyboards&lt;/td&gt;
&lt;td&gt;Always provide &lt;code&gt;tabIndex&lt;/code&gt; and &lt;code&gt;onKeyDown&lt;/code&gt; handlers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validate early&lt;/td&gt;
&lt;td&gt;Test with WAVE, NVDA, VoiceOver&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>webdev</category>
      <category>html</category>
      <category>a11y</category>
      <category>frontend</category>
    </item>
    <item>
      <title>🛠️ Fixing Common Accessibility Issues – Alt Text, Contrast, Headings &amp; Forms</title>
      <dc:creator>Kedar Kulkarni</dc:creator>
      <pubDate>Sat, 12 Jul 2025 04:03:30 +0000</pubDate>
      <link>https://forem.com/kedar7/fixing-common-accessibility-issues-alt-text-contrast-headings-forms-p9m</link>
      <guid>https://forem.com/kedar7/fixing-common-accessibility-issues-alt-text-contrast-headings-forms-p9m</guid>
      <description>&lt;p&gt;In Part 1, we explored the basics of accessibility and how to create a solid semantic HTML foundation. Now, let’s move forward by identifying and fixing the &lt;strong&gt;most common accessibility problems&lt;/strong&gt; that appear on real-world websites.&lt;/p&gt;

&lt;p&gt;These small fixes can drastically improve usability and compliance with &lt;strong&gt;WCAG Level A and AA&lt;/strong&gt; standards.&lt;/p&gt;




&lt;h3&gt;
  
  
  🖼️ 1. Missing or Inaccurate Alt Text for Images
&lt;/h3&gt;

&lt;p&gt;Images must include meaningful alternative text (&lt;code&gt;alt&lt;/code&gt;) to describe their purpose to screen readers and assistive tools.&lt;/p&gt;

&lt;h4&gt;
  
  
  ❌ Common Problems
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Missing &lt;code&gt;alt&lt;/code&gt; attribute&lt;/li&gt;
&lt;li&gt;Decorative images without &lt;code&gt;alt=""&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Redundant alt text (e.g., same as caption or nearby text)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ✅ Best Practices
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Describe the &lt;em&gt;function&lt;/em&gt; of the image, not the appearance.&lt;/li&gt;
&lt;li&gt;If an image is purely decorative, use &lt;code&gt;alt=""&lt;/code&gt; to hide it from screen readers.&lt;/li&gt;
&lt;li&gt;Don't duplicate nearby content.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  🧪 Example
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Bad: missing alt --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"search-icon.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Good: functional alt --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"search-icon.png"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Search"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Decorative image --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"divider.png"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🛠️ &lt;strong&gt;Tool Tip&lt;/strong&gt;: Use &lt;a href="https://wave.webaim.org/" rel="noopener noreferrer"&gt;WAVE&lt;/a&gt; to detect missing or redundant alt text.&lt;/p&gt;




&lt;h3&gt;
  
  
  🎨 2. Poor Color Contrast
&lt;/h3&gt;

&lt;p&gt;Low contrast between text and background colors makes content unreadable for users with visual impairments or color blindness.&lt;/p&gt;

&lt;h4&gt;
  
  
  ❌ Common Issue
&lt;/h4&gt;

&lt;p&gt;Text blends into the background due to insufficient contrast.&lt;/p&gt;

&lt;h4&gt;
  
  
  ✅ Fix It
&lt;/h4&gt;

&lt;p&gt;Ensure a &lt;strong&gt;contrast ratio of at least 4.5:1&lt;/strong&gt; for normal text, and &lt;strong&gt;3:1&lt;/strong&gt; for large text.&lt;/p&gt;

&lt;h4&gt;
  
  
  🔧 Example
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Too light */&lt;/span&gt;
&lt;span class="nt"&gt;color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;#cccccc&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;#ffffff&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c"&gt;/* Better */&lt;/span&gt;
&lt;span class="nt"&gt;color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;#333333&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;#ffffff&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the &lt;a href="https://wave.webaim.org/" rel="noopener noreferrer"&gt;WAVE contrast checker&lt;/a&gt; or &lt;a href="https://webaim.org/resources/contrastchecker/" rel="noopener noreferrer"&gt;WebAIM contrast tool&lt;/a&gt; to validate.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧩 3. Improper Heading Structure
&lt;/h3&gt;

&lt;p&gt;Headings help screen reader users understand the page structure and quickly navigate between sections.&lt;/p&gt;

&lt;h4&gt;
  
  
  ❌ Common Mistakes
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Skipping heading levels (e.g., &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; → &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Using headings for styling only&lt;/li&gt;
&lt;li&gt;Missing &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; altogether&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ✅ Best Practices
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;only one &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;&lt;/strong&gt; per page, usually as the page title.&lt;/li&gt;
&lt;li&gt;Maintain a logical hierarchy: &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; → &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; → &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;, and so on.&lt;/li&gt;
&lt;li&gt;Don’t skip levels.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  🧪 Example
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Correct order --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Page Title&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Section 1&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Sub-section&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Skipped order (bad) --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Page Title&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Sub-section&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt; &lt;span class="c"&gt;&amp;lt;!-- Skipped h2 --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🧠 Use the WAVE tool to view the heading outline visually and fix skipped levels.&lt;/p&gt;




&lt;h3&gt;
  
  
  📝 4. Form Inputs Without Labels
&lt;/h3&gt;

&lt;p&gt;Unlabeled form controls are unusable with screen readers and keyboard navigation. Screen readers rely on &lt;code&gt;label&lt;/code&gt; associations to describe the purpose of each input field.&lt;/p&gt;

&lt;h4&gt;
  
  
  ❌ Issues
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;No &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; element&lt;/li&gt;
&lt;li&gt;Only placeholder used (not accessible)&lt;/li&gt;
&lt;li&gt;Labels are not correctly associated&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ✅ Fix It
&lt;/h4&gt;

&lt;p&gt;There are two valid ways to associate labels:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Using &lt;code&gt;for&lt;/code&gt; and &lt;code&gt;id&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wrapping input inside the &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  🧪 Examples
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Good with for/id --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Email:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Good with wrapping --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;
  Email:
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Using ARIA --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Enter your email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;❗ Don’t rely only on &lt;code&gt;placeholder&lt;/code&gt; — it disappears after input and is not read consistently by assistive tools.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔍 5. Keyboard Navigation Failures
&lt;/h3&gt;

&lt;p&gt;Many users rely on keyboards (not mice) to interact with websites. &lt;strong&gt;All interactive elements must be reachable via the &lt;code&gt;Tab&lt;/code&gt; key&lt;/strong&gt; and should show a visible focus state.&lt;/p&gt;

&lt;h4&gt;
  
  
  ✅ Keyboard Navigation Checklist:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Can you tab to links, buttons, form fields, and controls?&lt;/li&gt;
&lt;li&gt;Does each element show a visual outline when focused?&lt;/li&gt;
&lt;li&gt;Can you tab &lt;em&gt;out&lt;/em&gt; of all interactive elements? (No “keyboard traps”)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧪 Test it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open your site&lt;/li&gt;
&lt;li&gt;Hit &lt;code&gt;Tab&lt;/code&gt; repeatedly&lt;/li&gt;
&lt;li&gt;Observe what gets focus and in what order&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🛠️ Use &lt;code&gt;tabindex="0"&lt;/code&gt; on custom elements to include them in the natural tab flow.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧾 Summary Checklist
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;✅ Fix&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alt Text&lt;/td&gt;
&lt;td&gt;Add meaningful &lt;code&gt;alt&lt;/code&gt; for functional images, &lt;code&gt;alt=""&lt;/code&gt; for decorative&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contrast&lt;/td&gt;
&lt;td&gt;Maintain minimum contrast ratio (4.5:1 for normal text)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Headings&lt;/td&gt;
&lt;td&gt;Use semantic headings in correct order; don’t skip levels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Labels&lt;/td&gt;
&lt;td&gt;Associate each input with a visible or accessible label&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keyboard&lt;/td&gt;
&lt;td&gt;Make sure all functionality works via keyboard only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  🔄 Coming Up: Building Accessible Widgets with ARIA in React (Blog 3)
&lt;/h3&gt;

&lt;p&gt;Next, we’ll explore &lt;strong&gt;ARIA roles, states, and properties&lt;/strong&gt; to build accessible custom components like dropdowns, modals, and toggle buttons — especially in &lt;strong&gt;React apps&lt;/strong&gt;.&lt;/p&gt;




</description>
      <category>webdev</category>
      <category>html</category>
      <category>a11y</category>
      <category>frontend</category>
    </item>
    <item>
      <title>✨ A Beginner's Guide to Web Accessibility – WCAG, Easy Checks &amp; Semantic HTML</title>
      <dc:creator>Kedar Kulkarni</dc:creator>
      <pubDate>Sat, 12 Jul 2025 04:02:03 +0000</pubDate>
      <link>https://forem.com/kedar7/a-beginners-guide-to-web-accessibility-wcag-easy-checks-semantic-html-2936</link>
      <guid>https://forem.com/kedar7/a-beginners-guide-to-web-accessibility-wcag-easy-checks-semantic-html-2936</guid>
      <description>&lt;p&gt;Creating inclusive digital experiences means building websites that work for &lt;em&gt;everyone&lt;/em&gt;, including individuals with physical, sensory, or cognitive impairments. Web accessibility isn’t just an option—it’s a foundational principle of good design. This post marks the beginning of a three-part series designed to help developers build accessible websites from the ground up.&lt;/p&gt;




&lt;h3&gt;
  
  
  🌐 What Is Web Accessibility?
&lt;/h3&gt;

&lt;p&gt;Web accessibility ensures that digital products can be understood, navigated, and interacted with by users who have diverse abilities. This includes people who:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are blind or have low vision&lt;/li&gt;
&lt;li&gt;Are deaf or hard of hearing&lt;/li&gt;
&lt;li&gt;Use assistive technologies (e.g., screen readers, keyboard-only navigation)&lt;/li&gt;
&lt;li&gt;Experience cognitive or neurological conditions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By making our websites more accessible, we also improve usability for &lt;em&gt;all&lt;/em&gt; users—not just those with disabilities.&lt;/p&gt;




&lt;h3&gt;
  
  
  📘 WCAG Compliance Levels Explained
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Web Content Accessibility Guidelines (WCAG)&lt;/strong&gt; provide a structured approach to making web content accessible. These standards define three levels of conformance:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Level&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Who Benefits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;Basic accessibility&lt;/td&gt;
&lt;td&gt;Covers essential needs of users with disabilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AA&lt;/td&gt;
&lt;td&gt;Recommended for most organizations&lt;/td&gt;
&lt;td&gt;Addresses the majority of common barriers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AAA&lt;/td&gt;
&lt;td&gt;Highest standard (difficult to meet)&lt;/td&gt;
&lt;td&gt;Supports a wide range of impairments&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🧪 &lt;strong&gt;Examples&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AAA&lt;/strong&gt;: w3.org, bbc.com, mit.edu&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AA&lt;/strong&gt;: google.com, microsoft.com, apple.com, india.gov.in&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🛠️ Setting Up a Simple Accessible HTML Page
&lt;/h3&gt;

&lt;p&gt;Let’s begin with a basic project that meets Level A requirements.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Create a folder for your project
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;myweb
&lt;span class="nb"&gt;cd &lt;/span&gt;myweb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Build a semantic &lt;code&gt;index.html&lt;/code&gt; file
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Getting Started with Accessibility&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Welcome to Our Accessible Site&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#home"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;What is Accessibility?&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Why It Matters&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;footer&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#contact"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Contact Us&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: View it using Live Server in VS Code
&lt;/h4&gt;




&lt;h3&gt;
  
  
  🔍 Quick Accessibility Audit: Easy Checks
&lt;/h3&gt;

&lt;p&gt;W3C offers a set of informal checks called &lt;strong&gt;Easy Checks&lt;/strong&gt; to help anyone quickly evaluate a page’s accessibility—even without expert knowledge.&lt;/p&gt;

&lt;h4&gt;
  
  
  ✅ What It Covers:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Titles&lt;/strong&gt;: Ensure each page has a clear and specific &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image Descriptions&lt;/strong&gt;: Use meaningful &lt;code&gt;alt&lt;/code&gt; attributes for all images.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headings&lt;/strong&gt;: Use heading tags in a logical order, without skipping levels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text Contrast&lt;/strong&gt;: Ensure sufficient color contrast between text and background.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keyboard Navigation&lt;/strong&gt;: All functions should be usable via the keyboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forms&lt;/strong&gt;: Every form input must be associated with a visible or hidden &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🔧 Tools for Manual Accessibility Checks
&lt;/h3&gt;

&lt;h4&gt;
  
  
  📌 &lt;a href="https://wave.webaim.org/" rel="noopener noreferrer"&gt;WAVE by WebAIM&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;WAVE is a browser-based accessibility evaluator that flags issues like missing alt text, low contrast, and improper heading order.&lt;/p&gt;

&lt;h4&gt;
  
  
  🧪 Browser Developer Tools
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Use the Inspector to verify &lt;code&gt;alt&lt;/code&gt; attributes on images.&lt;/li&gt;
&lt;li&gt;Test keyboard tab navigation to ensure elements receive focus.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🧠 Why Semantic HTML Is Crucial
&lt;/h3&gt;

&lt;p&gt;Semantic HTML elements give structure and meaning to your content. They’re recognized by browsers, assistive technologies, and search engines alike.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Identifies the page’s header section&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wraps navigation links&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Denotes primary page content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Groups related content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;footer&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Marks the page’s footer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Connects text to form inputs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preferred over &lt;code&gt;div&lt;/code&gt; for clicks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🔴 &lt;strong&gt;Avoid using &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; for layout unless no semantic alternative exists&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  🎯 Final Thoughts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Accessibility benefits everyone, not just those with disabilities.&lt;/li&gt;
&lt;li&gt;Starting with semantic HTML and proper structure makes a huge difference.&lt;/li&gt;
&lt;li&gt;Use tools like &lt;strong&gt;WAVE&lt;/strong&gt; and &lt;strong&gt;Easy Checks&lt;/strong&gt; for quick wins.&lt;/li&gt;
&lt;li&gt;Aim for at least &lt;strong&gt;WCAG Level A&lt;/strong&gt;; strive for &lt;strong&gt;AA&lt;/strong&gt; as your standard.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🚀 Coming Up: Common Accessibility Mistakes and How to Fix Them (Blog 2)
&lt;/h3&gt;

&lt;p&gt;In the next part of the series, we’ll dive into the most frequent issues developers face—like poor contrast, unlabeled form fields, and heading structure problems—and how to resolve them with real code examples.&lt;/p&gt;




</description>
      <category>webdev</category>
      <category>html</category>
      <category>a11y</category>
    </item>
    <item>
      <title>Simplifying Pagination in Angular with a Reusable Base Component</title>
      <dc:creator>Kedar Kulkarni</dc:creator>
      <pubDate>Mon, 14 Apr 2025 20:39:53 +0000</pubDate>
      <link>https://forem.com/kedar7/simplifying-pagination-in-angular-with-a-reusable-base-component-12jc</link>
      <guid>https://forem.com/kedar7/simplifying-pagination-in-angular-with-a-reusable-base-component-12jc</guid>
      <description>&lt;p&gt;Our objective is to abstract the repetitive aspects of pagination—such as tracking the current page, page size, total items, and loading state—into a base component. This base component will provide a standardized way to handle pagination, which can be extended by other components to implement their specific data-fetching logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating the BasePaginationComponent&lt;/strong&gt;&lt;br&gt;
Let's define a generic BasePaginationComponent class that handles the core pagination functionality:​&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { finalize } from 'rxjs/operators';
import { Observable } from 'rxjs';

export abstract class BasePaginationComponent&amp;lt;T&amp;gt; {
  data: T[] = [];
  currentPage = 1;
  pageSize = 10;
  totalItems = 0;
  isLoading = false;

  // Abstract method to fetch data; must be implemented by subclasses
  protected abstract fetchData(page: number, size: number): Observable&amp;lt;{ items: T[]; total: number }&amp;gt;;

  // Method to load data for a specific page
  loadPage(page: number): void {
    this.isLoading = true;
    this.fetchData(page, this.pageSize)
      .pipe(finalize(() =&amp;gt; (this.isLoading = false)))
      .subscribe(response =&amp;gt; {
        this.data = response.items;
        this.totalItems = response.total;
        this.currentPage = page;
      });
  }

  // Method to handle page change events (e.g., from a paginator component)
  onPageChange(page: number): void {
    this.loadPage(page);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this base component:​&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;data: Holds the current page's data items.​&lt;/li&gt;
&lt;li&gt;currentPage: Tracks the current page number.​&lt;/li&gt;
&lt;li&gt;pageSize: Defines the number of items per page.​&lt;/li&gt;
&lt;li&gt;totalItems: Stores the total number of items across all pages.​&lt;/li&gt;
&lt;li&gt;isLoading: Indicates whether a data fetch operation is in progress.​&lt;/li&gt;
&lt;li&gt;fetchData: An abstract method that must be implemented by subclasses to fetch data for a given page and page size.​&lt;/li&gt;
&lt;li&gt;loadPage: Handles the logic for loading data for a specific page.​&lt;/li&gt;
&lt;li&gt;onPageChange: A helper method to be called when the page changes, which in turn calls loadPage.​&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Implementing the PaginationControlsComponent&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';

@Component({
  selector: 'app-pagination-controls',
  templateUrl: './pagination-controls.component.html'
})
export class PaginationControlsComponent implements OnChanges {
  @Input() currentPage: number = 1;
  @Input() totalItems: number = 0;
  @Input() pageSize: number = 10;
  @Output() pageChange: EventEmitter&amp;lt;number&amp;gt; = new EventEmitter&amp;lt;number&amp;gt;();

  totalPages: number = 0;
  pages: number[] = [];

  ngOnChanges(changes: SimpleChanges): void {
    this.totalPages = Math.ceil(this.totalItems / this.pageSize);
    this.pages = Array.from({ length: this.totalPages }, (_, i) =&amp;gt; i + 1);
  }

  changePage(page: number): void {
    if (page &amp;gt;= 1 &amp;amp;&amp;amp; page &amp;lt;= this.totalPages &amp;amp;&amp;amp; page !== this.currentPage) {
      this.pageChange.emit(page);
    }
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Extending the Base Component&lt;/strong&gt;&lt;br&gt;
Now, let's create a component that extends BasePaginationComponent to display a list of users:​&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { BasePaginationComponent } from './base-pagination.component';
import { UserService } from './user.service';
import { User } from './user.model';

@Component({
  selector: 'app-user-list',
  templateUrl: './user-list.component.html'
})
export class UserListComponent extends BasePaginationComponent&amp;lt;User&amp;gt; implements OnInit {
  constructor(private userService: UserService) {
    super();
  }

  ngOnInit(): void {
    this.loadPage(this.currentPage);
  }

  protected fetchData(page: number, size: number): Observable&amp;lt;{ items: User[]; total: number }&amp;gt; {
    return this.userService.getUsers(page, size);
  }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example:​&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UserListComponent extends BasePaginationComponent, specifying User as the data type.​&lt;/li&gt;
&lt;li&gt;The fetchData method is implemented to fetch users from the UserService.​&lt;/li&gt;
&lt;li&gt;The template displays the list of users and includes a custom app-pagination-controls component to handle pagination UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Handling Edge Cases in Your Pagination System&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While the basic implementation works well, a production-ready pagination system should address these common edge cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Large datasets&lt;/strong&gt;: Display a limited range of pages (first, last, and a few around current) with ellipses instead of showing all page numbers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Navigation boundaries&lt;/strong&gt;: Disable Previous/Next buttons at first/last pages, and hide pagination entirely for single-page results&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Empty results&lt;/strong&gt;: Provide user feedback when no items exist instead of showing empty pagination controls&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Page size changes&lt;/strong&gt;: Reset to first page when page size changes to ensure consistent user experience&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;URL integration&lt;/strong&gt;: Consider syncing pagination state with URL parameters for bookmarking and sharing specific pages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive design&lt;/strong&gt;: Adapt controls for smaller screens with simplified mobile-friendly navigation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: Implement keyboard navigation and proper ARIA labels for inclusive user experience&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error handling&lt;/strong&gt;: Gracefully manage network failures during server-side pagination operations&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>angular</category>
      <category>javascript</category>
      <category>rxjs</category>
    </item>
    <item>
      <title>Cleaning Up Angular Form Submissions: A Reusable Approach</title>
      <dc:creator>Kedar Kulkarni</dc:creator>
      <pubDate>Mon, 14 Apr 2025 20:04:16 +0000</pubDate>
      <link>https://forem.com/kedar7/cleaning-up-angular-form-submissions-a-reusable-approach-40aa</link>
      <guid>https://forem.com/kedar7/cleaning-up-angular-form-submissions-a-reusable-approach-40aa</guid>
      <description>&lt;p&gt;Working with forms in Angular often involves repeating the same steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Collecting form data​&lt;/li&gt;
&lt;li&gt;Making an API call​&lt;/li&gt;
&lt;li&gt;Managing loading states​&lt;/li&gt;
&lt;li&gt;Handling success and error responses​&lt;/li&gt;
&lt;li&gt;Disabling the submit button during processing​&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you find yourself duplicating this logic across multiple components, consider a more efficient approach.​ &lt;/p&gt;

&lt;p&gt;Typically, a form submission in Angular might look like this:​&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onSubmit() {
  this.isSubmitting = true;
  const payload = this.form.value;

  this.api.saveUser(payload).pipe(
    finalize(() =&amp;gt; this.isSubmitting = false)
  ).subscribe({
    next: res =&amp;gt; console.log('Success', res),
    error: err =&amp;gt; console.error('Error', err)
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While functional, this pattern can become repetitive and more challenging to maintain as your application grows.​&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introducing a Reusable Base Component&lt;/strong&gt;&lt;br&gt;
To streamline this process, we can create a base component that encapsulates the common submission logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// base-submit.component.ts
export abstract class BaseSubmitComponent&amp;lt;T = any&amp;gt; {
  isSubmitting = false;

  // Method to create the payload
  abstract createPayload(): T;

  // Method to handle successful submission
  abstract onSubmitSuccess(response: any): void;

  protected submit(apiFn: (payload: T) =&amp;gt; Observable&amp;lt;any&amp;gt;) {
    this.isSubmitting = true;
    const payload = this.createPayload();

    apiFn(payload).pipe(
      finalize(() =&amp;gt; this.isSubmitting = false)
    ).subscribe({
      next: res =&amp;gt; this.onSubmitSuccess(res),
      error: err =&amp;gt; this.handleError(err)
    });
  }

  protected handleError(err: any) {
    console.error('Submit error:', err);
    // Implement your error handling logic here
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this base component, individual form components can focus on their specific logic:​&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export class UserFormComponent extends BaseSubmitComponent&amp;lt;UserPayload&amp;gt; {
  form = this.fb.group({
    name: [''],
    email: ['']
  });

  constructor(private fb: FormBuilder, private api: ApiService) {
    super();
  }

  createPayload(): UserPayload {
    return this.form.value;
  }

  onSubmitSuccess(response: any) {
    console.log('User saved successfully:', response);
    // Additional success handling
  }

  onSubmit() {
    this.submit(payload =&amp;gt; this.api.saveUser(payload));
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Advantages of This Approach&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistency: Ensures uniform handling of submissions across components.​&lt;/li&gt;
&lt;li&gt;Maintainability: Centralizes common logic, making updates easier.​&lt;/li&gt;
&lt;li&gt;Clarity: Keeps individual components focused on their unique responsibilities.​&lt;/li&gt;
&lt;li&gt;Extensibility: Allows for easy addition of features like validation checks or pre-submission hooks.​&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Enhancements to Consider&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shared UI Components: Create reusable components for buttons or form fields that integrate with the submission state.​&lt;/li&gt;
&lt;li&gt;Centralized Error Handling: Implement a global service for displaying error messages or notifications.​&lt;/li&gt;
&lt;li&gt;Form Validation: Incorporate validation logic to prevent invalid submissions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Edge Cases to Handle&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When implementing this form submission pattern, consider these important scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom Error Handling&lt;/strong&gt;: Allow components to implement their error handling via an &lt;code&gt;onSubmitError&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pre-submission Validation&lt;/strong&gt;: Add validation checks before API calls to prevent invalid submissions.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cancellable Requests&lt;/strong&gt;: Implement a way to cancel ongoing submissions if users navigate away.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form Reset Logic&lt;/strong&gt;: Add standardized methods to reset forms after successful submissions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Submission Throttling&lt;/strong&gt;: Prevent duplicate submissions from rapid clicking.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>designpatterns</category>
    </item>
  </channel>
</rss>
