Skip to content
beginnerPhase 30 · HTML

HTML Accessibility

Build accessible HTML with ARIA roles, alt text, and semantic structure.

45m
0 problems
Topic Progress0%

ARIA Roles

ARIA (Accessible Rich Internet Applications) roles help screen readers understand custom components.

Landmark Roles

<!-- Implicit landmarks (use native elements) -->
<header>      <!-- role="banner" -->
<nav>         <!-- role="navigation" -->
<main>        <!-- role="main" -->
<aside>       <!-- role="complementary" -->
<footer>      <!-- role="contentinfo" -->

<!-- Explicit landmarks (when native elements don't fit) -->
<div role="search">
    <input type="search" aria-label="Search">
</div>
<div role="form" aria-label="Contact form">
    <!-- form content -->
</div>

Widget Roles

<!-- Tab interface -->
<div role="tablist">
    <button role="tab" aria-selected="true" aria-controls="panel1">Tab 1</button>
    <button role="tab" aria-selected="false" aria-controls="panel2">Tab 2</button>
</div>
<div role="tabpanel" id="panel1">Content 1</div>
<div role="tabpanel" id="panel2" hidden>Content 2</div>

<!-- Dialog -->
<div role="dialog" aria-labelledby="dialog-title" aria-modal="true">
    <h2 id="dialog-title">Confirm Action</h2>
    <p>Are you sure?</p>
    <button>Yes</button>
    <button>No</button>
</div>

<!-- Alert -->
<div role="alert">
    Error: Invalid email address
</div>

<!-- Progress -->
<div role="progressbar" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100">
    50% complete
</div>

Common ARIA Attributes

Attribute Purpose Example
aria-label Label for element aria-label="Close"
aria-labelledby ID of label element aria-labelledby="title"
aria-describedby ID of description aria-describedby="help-text"
aria-hidden Hide from screen readers aria-hidden="true"
aria-expanded Expanded state aria-expanded="false"
aria-selected Selected state aria-selected="true"
aria-checked Checked state aria-checked="mixed"
aria-disabled Disabled state aria-disabled="true"
aria-required Required field aria-required="true"
aria-live Live region aria-live="polite"

ARIA Best Practices

<!-- ❌ Don't use ARIA when native HTML works -->
<div role="button" onclick="...">Click</div>
<!-- ✅ Use native button -->
<button onclick="...">Click</button>

<!-- ❌ Don't add ARIA to semantic elements -->
<nav aria-label="navigation">...</nav>
<!-- ✅ Use aria-label only when needed -->
<nav aria-label="Main">...</nav>

<!-- ✅ Use aria-labelledby for complex labels -->
<section aria-labelledby="section-title">
    <h2 id="section-title">Section Title</h2>
    <p>Content...</p>
</section>

Alt Text

Alternative text makes images accessible to screen readers and when images fail to load.

Alt Text Rules

<!-- ❌ Bad alt text -->
<img src="photo.jpg" alt="">
<img src="photo.jpg" alt="image">
<img src="photo.jpg" alt="photo.jpg">
<img src="photo.jpg" alt="photo of a dog sitting on a chair in a park on a sunny day with trees in the background and a fence">

<!-- ✅ Good alt text -->
<img src="dog.jpg" alt="Golden retriever sitting in park">
<img src="chart.png" alt="Sales increased 25% in Q4">
<img src="logo.png" alt="">

When to Use Empty Alt

<!-- Decorative images: empty alt -->
<img src="decoration.png" alt="">

<!-- Functional images: descriptive alt -->
<img src="search-icon.png" alt="Search">

<!-- Informative images: describe content -->
<img src="infographic.png" alt="Infographic showing 5 steps to clean code">

<!-- Images with text: include all text -->
<img src="banner.png" alt="Sale! 50% off all items">

Complex Images

<!-- Simple image with long description -->
<img src="chart.png" alt="Q4 sales chart" aria-describedby="chart-desc">
<div id="chart-desc">
    <p>Sales chart showing:
    - October: $10,000
    - November: $15,000
    - December: $20,000</p>
</div>

<!-- Image in figure -->
<figure>
    <img src="diagram.png" alt="Architecture diagram">
    <figcaption>Figure 1: System architecture showing client-server communication</figcaption>
</figure>

Alt Text for Different Contexts

Image Type Alt Text Approach
Informative Describe the content
Decorative Empty alt (alt="")
Functional Describe the function
Text in image Include all text
Complex Use aria-describedby
Group Alt for main + descriptions for each

Testing Alt Text

<!-- Test: Would this make sense read aloud? -->
<img src="photo.jpg" alt="Photo">  <!-- ❌ No -->
<img src="photo.jpg" alt="Team meeting in conference room">  <!-- ✅ Yes -->

<!-- Test: Is it concise? -->
<img src="chart.png" alt="Sales chart">  <!-- Too vague -->
<img src="chart.png" alt="Q4 sales up 25%">  <!-- ✅ Good -->

Accessible Forms

Accessible forms ensure all users can interact with form controls.

Labels are Essential

<!-- ❌ No label (inaccessible) -->
<input type="email" placeholder="Email">

<!-- ✅ Explicit label (best) -->
<label for="email">Email:</label>
<input type="email" id="email" name="email">

<!-- ✅ Implicit label -->
<label>
    Email:
    <input type="email" name="email">
</label>

<!-- ✅ aria-label (when visual label isn't possible) -->
<input type="email" aria-label="Email address">

Required Fields

<!-- Visual indicator + aria-required -->
<label for="name">
    Name <span aria-hidden="true">*</span>
</label>
<input type="text" id="name" name="name" required aria-required="true">

<!-- Required with description -->
<label for="password">Password</label>
<input type="password" id="password" required aria-required="true" aria-describedby="password-req">
<p id="password-req">Must be at least 8 characters</p>

Error Messages

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

<!-- Live region for dynamic errors -->
<div aria-live="polite">
    <!-- Errors announced to screen readers -->
</div>

Fieldsets and Legends

<!-- Group related fields -->
<fieldset>
    <legend>Personal Information</legend>
    <label for="name">Name:</label>
    <input type="text" id="name">
    <label for="email">Email:</label>
    <input type="email" id="email">
</fieldset>

<!-- Radio button groups -->
<fieldset>
    <legend>Preferred contact method</legend>
    <input type="radio" id="contact-email" name="contact" value="email">
    <label for="contact-email">Email</label>
    <input type="radio" id="contact-phone" name="contact" value="phone">
    <label for="contact-phone">Phone</label>
</fieldset>

Form Instructions

<!-- Provide clear instructions -->
<label for="password">Password</label>
<input type="password" id="password" aria-describedby="password-help">
<p id="password-help">Must be at least 8 characters with one uppercase letter</p>

<!-- Required field indicator -->
<p><span aria-hidden="true">*</span> indicates required field</p>

<!-- Error summary -->
<div role="alert" aria-live="assertive">
    <h3>Please fix the following errors:</h3>
    <ul>
        <li><a href="#email">Email is required</a></li>
        <li><a href="#password">Password must be 8+ characters</a></li>
    </ul>
</div>

Practice Problems

0/3solved
Build HTML Accessibility Component

Create a reusable React component implementing HTML Accessibility. Include proper state management and accessibility.

Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where needed
HTML Accessibility Testing

Write unit and integration tests for HTML Accessibility using React Testing Library.

Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility tests
HTML Accessibility Performance

Optimize HTML Accessibility for performance. Consider memoization, code splitting, and bundle size.

Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysis

Quiz

1. What is the first rule of ARIA?

Question 1 options

2. When should you use alt="" (empty alt)?

Question 2 options

3. Why are labels important for forms?

Question 3 options

4. What does aria-live="polite" do?

Question 4 options

Flashcards

Question

What is the first rule of ARIA?

Answer

If you can use a native HTML element with the semantics you need, do so. ARIA is a fallback, not a first choice.

Question

What is the purpose of alt text?

Answer

Provides alternative text for screen readers and when images fail to load. Should describe the image content or be empty for decorative images.

Question

How do you make forms accessible?

Answer

Use labels for all controls, provide clear instructions, indicate required fields, and use fieldset/legend for groups.

Question

What does aria-hidden="true" do?

Answer

Hides the element from screen readers. Use for decorative content that doesn't add meaning.

Question

What is HTML Accessibility?

Answer

HTML Accessibility is a key concept in frontend development.

Revision Notes

Key Takeaways

  • 1.Use native HTML elements before ARIA
  • 2.Always provide alt text for images
  • 3.Labels are essential for form accessibility
  • 4.Use ARIA roles to enhance semantics
  • 5.Test with screen readers and keyboard navigation

Interview Tips

  • Know the first rule of ARIA
  • Understand when to use empty alt vs descriptive alt
  • Be familiar with common ARIA attributes
  • Know how to make forms accessible

Cheat Sheet

HTML Accessibility Cheat Sheet

ARIA Principles:

  1. Use native HTML first
  2. Don't break native semantics
  3. All interactive elements must be keyboard accessible
  4. Don't use role="presentation" or aria-hidden="true" on focusable elements

Landmarks:

  • header → banner
  • nav → navigation
  • main → main
  • aside → complementary
  • footer → contentinfo

Key ARIA Attributes:

  • aria-label: Label for element
  • aria-labelledby: ID of label
  • aria-describedby: ID of description
  • aria-hidden: Hide from screen readers
  • aria-expanded: Expanded state
  • aria-live: Announce changes

Forms:

  • Always use labels
  • Indicate required fields
  • Provide clear error messages
  • Use fieldset/legend for groups

Images:

  • Informative: descriptive alt
  • Decorative: empty alt
  • Functional: describe function