CodeFrog
Accessibility Best Practices
← Back to CodeFrog

Accessibility Best Practices

Overview

This guide combines best practices for both accessibility and HTML validation to help you build websites that are usable, standards-compliant, and performant.

HTML Validation Best Practices

Use Semantic HTML

Semantic HTML helps both accessibility and SEO:

<!-- Bad: Generic divs -->
<div class="header">...</div>
<div class="content">...</div>
<div class="footer">...</div>

<!-- Good: Semantic elements -->
<header>...</header>
<main>...</main>
<footer>...</footer>

Benefits:

Proper Heading Hierarchy

Always maintain logical heading order:

<!-- Bad: Skipping levels -->
<h1>Main Title</h1>
<h3>Subsection</h3>

<!-- Good: Sequential hierarchy -->
<h1>Main Title</h1>
<h2>Section</h2>
<h3>Subsection</h3>

Why it matters:

Valid HTML Structure

Ensure your HTML is valid:

Tools:

Accessibility Best Practices

Images and Media

Alt Text Guidelines

Descriptive alt text for informative images:

<img src="chart.png" alt="Sales increased 25% from Q1 to Q2, shown in a bar chart">

Empty alt text for decorative images:

<img src="decorative-border.png" alt="">

Functional images (buttons, links):

<a href="/download">
  <img src="download-icon.png" alt="Download PDF">
</a>

Video and Audio

Forms and Inputs

Label All Form Fields

<!-- Bad -->
<input type="email" name="email" placeholder="Email">

<!-- Good -->
<label for="email">Email Address</label>
<input type="email" id="email" name="email">
<fieldset>
  <legend>Shipping Address</legend>
  <label for="street">Street</label>
  <input type="text" id="street" name="street">
  <!-- More fields -->
</fieldset>

Error Messages

<label for="email">Email</label>
<input type="email" id="email" aria-describedby="email-error">
<span id="email-error" role="alert">Please enter a valid email address</span>

Color and Contrast

Minimum Contrast Ratios

Don’t Rely on Color Alone

<!-- Bad: Color only -->
<span style="color: red">Required field</span>

<!-- Good: Color + indicator -->
<span style="color: red">* Required field</span>

Keyboard Navigation

All Interactive Elements Must Be Keyboard Accessible

Focus Management

<!-- Skip to main content -->
<a href="#main-content" class="skip-link">Skip to main content</a>

Keyboard Shortcuts

ARIA (Accessible Rich Internet Applications)

Always Prefer Native HTML Over ARIA

The W3C’s first rule of ARIA use states: if you can use a native HTML element with the semantics and behavior you require already built in, use it instead of adding ARIA. ARIA was designed as a bridge for cases where HTML doesn’t have the right element — it was never meant to replace semantic HTML.

<!-- Best: Native HTML element -->
<button>Close</button>

<!-- Acceptable when no native element exists -->
<div role="button" tabindex="0" aria-label="Close dialog">×</div>

Common replacements — use native elements instead of ARIA:

Instead of Use
<div role="button"> <button>
<div role="dialog"> <dialog>
<div role="navigation"> <nav>
aria-expanded + JS <details> and <summary>
<div aria-live="polite"> <output>
aria-required="true" required attribute
aria-disabled="true" disabled attribute

Native elements provide keyboard behavior, focus management, mobile adaptations, and screen reader support automatically — with less code and fewer potential bugs.

For a comprehensive guide with code examples, see Why Use Semantic HTML (Even When Automated Tests Pass).

Use ARIA When Native HTML Isn’t Enough

ARIA remains valuable for complex widgets (tree views, data grids), supplementary context (aria-describedby, aria-label for icon-only buttons), and state communication (aria-expanded, aria-current).

Common ARIA Patterns

Landmarks (use aria-label to distinguish multiple landmarks of the same type):

<nav aria-label="Main navigation">
<main aria-label="Main content">
<aside aria-label="Related articles">

Live Regions:

<div role="status" aria-live="polite">Item added to cart</div>
<div role="alert" aria-live="assertive">Error: Invalid input</div>

States:

<button aria-expanded="false" aria-controls="menu">Menu</button>
<div id="menu" aria-hidden="true">...</div>

Dynamic Content

Announce Changes to Screen Readers

When content changes dynamically:

<div role="status" aria-live="polite" id="status">
  <!-- Status updates appear here -->
</div>

Loading States

<button aria-busy="true" aria-label="Loading...">Submit</button>

Combining HTML Validation and Accessibility

Semantic HTML = Better Accessibility

Valid, semantic HTML is inherently more accessible:

Performance Benefits

Valid HTML often means:

SEO Benefits

Search engines favor:

Testing Strategy

Automated Testing

  1. CodeFrog Accessibility Testing: Run on every build
  2. HTML Validation: Check before deployment
  3. CI/CD Integration: Automate in your pipeline

Manual Testing

  1. Screen Reader Testing: Use VoiceOver, NVDA, or JAWS
  2. Keyboard Navigation: Test without a mouse
  3. Browser Testing: Test across different browsers
  4. Mobile Testing: Test on actual devices

User Testing

Common Patterns

Accessible Modal Dialog

<div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
  <h2 id="dialog-title">Confirm Action</h2>
  <p>Are you sure you want to proceed?</p>
  <button>Cancel</button>
  <button>Confirm</button>
</div>

Accessible Navigation

<nav aria-label="Main navigation">
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about">About</a></li>
    <li><a href="/contact">Contact</a></li>
  </ul>
</nav>

Accessible Form

<form>
  <fieldset>
    <legend>Contact Information</legend>
    <label for="name">Name</label>
    <input type="text" id="name" name="name" required>
    
    <label for="email">Email</label>
    <input type="email" id="email" name="email" required
           aria-describedby="email-help">
    <small id="email-help">We'll never share your email</small>
  </fieldset>
  
  <button type="submit">Submit</button>
</form>

Maintenance

Regular Audits

Documentation

Continuous Improvement

External Resources


Following these best practices will help you build websites that are accessible, standards-compliant, and provide a great experience for all users.