Accessibility Considerations in Web Development
Ensuring web accessibility is essential for creating inclusive digital experiences. It benefits users with disabilities and improves overall user experience.
Ensuring web accessibility is essential for creating inclusive digital experiences. Accessibility not only benefits users with disabilities but also improves the overall user experience and expands your audience reach. This guide covers the importance of accessibility, techniques for making DOM manipulation accessible, the role of ARIA (Accessible Rich Internet Applications), and how to keep dynamic JavaScript widgets usable by everyone.
When you build interactivity with JavaScript — toggling content, selecting and updating elements, or modifying the document — you take on responsibility for the accessibility that the browser would otherwise provide for free with plain HTML. This chapter shows where that responsibility lies and how to meet it.
Creating Accessible Content
Importance of Accessibility in Web Development
Accessibility in web development ensures that all users, including those with disabilities, can access and interact with web content effectively. The World Health Organization estimates that over 1 billion people live with some form of disability. By making your web content accessible, you cater to a broader audience, improve usability, and comply with legal standards such as the Americans with Disabilities Act (ADA) and the Web Content Accessibility Guidelines (WCAG).
Benefits of Accessibility
- Inclusivity: Enables users with various disabilities to access information and services.
- SEO Improvement: Search engines often reward accessible websites with better rankings.
- Legal Compliance: Helps avoid potential legal issues related to accessibility standards.
- Enhanced Usability: Improves the overall user experience for all visitors, including those without disabilities.
Techniques for Making DOM Manipulation Accessible
Keyboard Navigation
Many people cannot use a mouse — they navigate with the keyboard, a switch device, or a screen reader that drives the keyboard. If a control only responds to clicks, those users are locked out. The rule of thumb: anything a mouse user can do, a keyboard user must be able to do too.
Ensure that all interactive elements are accessible via keyboard. Rely on the natural DOM order for tab navigation to maintain a logical flow. The tabindex attribute controls this:
tabindex="0"puts an element into the natural tab order (useful when you make a non-native element interactive).tabindex="-1"removes it from the tab order but lets you focus it programmatically withelement.focus().- Positive values like
tabindex="3"override the natural order and almost always cause confusion — avoid them.
Native elements such as <button>, <a href>, and form controls are keyboard-focusable by default, which is one of the strongest reasons to prefer them over clickable <div>s. Always ensure a visible focus indicator (the outline) is styled so keyboard users can clearly see which element is focused — never set outline: none without providing a replacement.
<!DOCTYPE html>
<html>
<head>
<title>Keyboard Navigation Example</title>
</head>
<body>
<h4>Press the 'Tab' key to navigate through the buttons!</h4>
<button>Button 1</button>
<button>Button 2</button>
<button>Button 3</button>
</body>
</html>This example relies on the natural DOM order for buttons, making it easier for keyboard users to navigate.
Accessible Interactive Components
This example demonstrates how to create an accessible accordion using ARIA roles and properties, and managing focus effectively.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Accessible Accordion Example</title>
<style>
.accordion {
border: 1px solid #ccc;
border-radius: 5px;
margin: 20px 0;
}
.accordion-header {
padding: 10px;
cursor: pointer;
background-color: #f0f0f0;
border-bottom: 1px solid #ccc;
width: 100%;
text-align: left;
}
.accordion-content {
display: none;
padding: 10px;
}
</style>
</head>
<body>
<h1>Accessible Accordion Example</h1>
<h4>Use your keyboard (Enter or Space key) to toggle the accordion!</h4>
<div class="accordion">
<button class="accordion-header" id="accordion-header-1" aria-controls="accordion-content-1" aria-expanded="false">
Section 1
</button>
<div class="accordion-content" id="accordion-content-1" role="region" aria-labelledby="accordion-header-1" tabindex="-1">
<p>This is the content of section 1.</p>
</div>
</div>
<div class="accordion">
<button class="accordion-header" id="accordion-header-2" aria-controls="accordion-content-2" aria-expanded="false">
Section 2
</button>
<div class="accordion-content" id="accordion-content-2" role="region" aria-labelledby="accordion-header-2" tabindex="-1">
<p>This is the content of section 2.</p>
</div>
</div>
<div class="accordion">
<button class="accordion-header" id="accordion-header-3" aria-controls="accordion-content-3" aria-expanded="false">
Section 3
</button>
<div class="accordion-content" id="accordion-content-3" role="region" aria-labelledby="accordion-header-3" tabindex="-1">
<p>This is the content of section 3.</p>
</div>
</div>
<script>
document.querySelectorAll('.accordion-header').forEach(header => {
header.addEventListener('click', function () {
const expanded = this.getAttribute('aria-expanded') === 'true';
this.setAttribute('aria-expanded', !expanded);
const content = document.getElementById(this.getAttribute('aria-controls'));
content.style.display = !expanded ? 'block' : 'none';
});
header.addEventListener('keydown', function (event) {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
this.click();
}
});
});
</script>
</body>
</html>- Accordion Structure: The accordion consists of headers that, when clicked, expand or collapse their associated content.
- Semantic HTML & ARIA:
- Native
<button>elements are used for headers to ensure built-in keyboard and screen reader support. aria-controlsassociates headers with their content.aria-expandedindicates the state of the accordion section.role="region"on the content sections identifies them as significant regions.
- Native
- Keyboard Accessibility:
- Event listeners handle
clickandkeydownevents to allow toggling the accordion using the keyboard (Enter or Space).
- Event listeners handle
Why this matters:
- Improved Usability: The accordion is usable via mouse and keyboard.
- Enhanced Accessibility: ARIA attributes communicate the state and structure to assistive technologies, making it accessible to screen reader users.
- Focus Management: Focus remains on the trigger button, following standard accordion patterns and preventing unexpected navigation jumps for keyboard users.
For deeper coverage of wiring up keyboard and click behavior, see Event handling in the DOM.
Semantic HTML
Use semantic HTML elements to convey the meaning and structure of content. This helps assistive technologies interpret and navigate web content effectively.
<!DOCTYPE html>
<html>
<head>
<title>Semantic HTML Example</title>
</head>
<body>
<header>
<h1>Main Heading</h1>
</header>
<nav>
<ul>
<li><a href="#section1">Section 1</a></li>
<li><a href="#section2">Section 2</a></li>
</ul>
</nav>
<main>
<section id="section1">
<h2>Section 1</h2>
<p>Content for section 1.</p>
</section>
<section id="section2">
<h2>Section 2</h2>
<p>Content for section 2.</p>
</section>
</main>
<footer>
<p>Footer content</p>
</footer>
</body>
</html>This example uses semantic HTML elements such as <header>, <nav>, <main>, <section>, and <footer> to define the structure of the page.
Text Alternatives
Screen readers cannot interpret images, icons, or canvas drawings — they read the text alternative you supply. Every meaningful image needs an alt attribute that describes its content or function. Decorative images that add no information should have an empty alt="" so the screen reader skips them rather than announcing a file name.
<!-- Meaningful image: describe it -->
<img src="chart.png" alt="Sales rose 40% from January to March" />
<!-- Decorative image: hide it from screen readers -->
<img src="divider.png" alt="" />
<!-- Icon-only button: label it -->
<button aria-label="Close dialog">×</button>When you generate images or icon buttons dynamically with JavaScript, set the alt or aria-label at the same time you create the element — never ship an unlabeled control.
Managing Focus in Dynamic Content
When JavaScript opens a dialog, reveals new content, or moves the user through a multi-step flow, you must move focus deliberately. Otherwise a keyboard or screen reader user is left at the old position with no idea that anything changed. The example below opens a modal, moves focus into it, traps focus so Tab cannot escape, and restores focus to the trigger button on close.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Accessible Modal Example</title>
<style>
.overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.5); }
.overlay.open { display: flex; align-items: center; justify-content: center; }
.dialog { background: #fff; padding: 20px; border-radius: 6px; min-width: 260px; }
</style>
</head>
<body>
<button id="open-btn">Open dialog</button>
<div class="overlay" id="overlay">
<div class="dialog" role="dialog" aria-modal="true" aria-labelledby="dialog-title">
<h2 id="dialog-title">Confirm action</h2>
<p>Are you sure you want to continue?</p>
<button id="confirm-btn">Confirm</button>
<button id="close-btn">Cancel</button>
</div>
</div>
<script>
const overlay = document.getElementById('overlay');
const openBtn = document.getElementById('open-btn');
const closeBtn = document.getElementById('close-btn');
let lastFocused = null;
function openDialog() {
lastFocused = document.activeElement; // remember the trigger
overlay.classList.add('open');
document.getElementById('confirm-btn').focus(); // move focus in
}
function closeDialog() {
overlay.classList.remove('open');
if (lastFocused) lastFocused.focus(); // restore focus
}
openBtn.addEventListener('click', openDialog);
closeBtn.addEventListener('click', closeDialog);
// Trap focus inside the dialog and close on Escape
overlay.addEventListener('keydown', function (event) {
if (event.key === 'Escape') { closeDialog(); return; }
if (event.key !== 'Tab') return;
const focusable = overlay.querySelectorAll('button');
const first = focusable[0];
const last = focusable[focusable.length - 1];
if (event.shiftKey && document.activeElement === first) {
event.preventDefault();
last.focus();
} else if (!event.shiftKey && document.activeElement === last) {
event.preventDefault();
first.focus();
}
});
</script>
</body>
</html>Key points: role="dialog" and aria-modal="true" tell assistive technology this is a modal, aria-labelledby gives it an accessible name, focus moves in on open and returns to the trigger on close, and Tab/Shift+Tab cycle within the dialog instead of escaping behind it. For more on programmatic focus, see Focusing: focus / blur.
ARIA (Accessible Rich Internet Applications)
More about ARIA
As you have learned so far, ARIA (Accessible Rich Internet Applications) is a set of attributes that can be added to HTML elements to improve accessibility for users of assistive technologies like screen readers. ARIA attributes help define roles, properties, and states of elements, making web applications more accessible.
The single most important rule of ARIA is: if a native HTML element with the behavior you need already exists, use it instead of recreating it with ARIA. A <button> is always better than <div role="button">, because the native button gives you keyboard activation, focus, and screen-reader semantics with zero JavaScript. ARIA does not add any behavior — it only changes how a screen reader describes an element. Reach for ARIA when no native element fits (custom tabs, sliders, tree views, live regions).
Using ARIA Attributes to Enhance Accessibility
ARIA Roles
ARIA roles define the type of element, helping assistive technologies understand its purpose.
<div role="button" aria-pressed="false">Toggle</div>This non-interactive element uses the aria-pressed state to indicate its toggle status.
ARIA Properties and States
ARIA properties and states provide additional information about elements.
<!DOCTYPE html>
<html>
<head>
<title>ARIA Example</title>
</head>
<body>
<div role="alert" id="live-region">
<!-- Dynamic content goes here -->
</div>
<script>
document.getElementById('live-region').textContent = "This is an important message.";
</script>
</body>
</html>This example uses ARIA properties to create a live region that announces important messages dynamically. A live region is an element whose changes the screen reader reads aloud automatically, without the user having to move focus to it — ideal for status updates, form errors, or chat messages.
You control how urgently the change is announced:
role="alert"(oraria-live="assertive") interrupts the user immediately — reserve it for errors and time-critical messages.aria-live="polite"waits until the user is idle before announcing — use it for non-urgent status like "Item added to cart".
<div aria-live="polite" id="status"></div>
<script>
// Updating the text content triggers the announcement
document.getElementById('status').textContent = 'Settings saved.';
</script>The live-region element must already exist in the DOM before you update it; if you inject the element and its text at the same time, many screen readers will miss the change.
Best Practices
- Use Semantic HTML: Always prefer semantic HTML elements to provide clear meaning and structure to content.
- Implement Keyboard Accessibility: Ensure that all interactive elements can be accessed and operated via keyboard.
- Manage Focus Effectively: Control the focus programmatically to guide users through dynamic content changes.
- Use ARIA Wisely: Apply ARIA roles, properties, and states to enhance, not replace, the semantics of native HTML elements.
- Test with Assistive Technologies: Regularly test your web applications with screen readers and other assistive technologies to ensure accessibility.
- Use Automated Testing Tools: Run checks with tools like axe or Lighthouse to catch common accessibility issues early.
Always ensure that your modals and other dynamic elements are accessible by managing focus effectively. Use JavaScript to trap focus within modals, cycling through focusable elements with the Tab key to prevent keyboard users from navigating outside the dialog unintentionally. This enhances accessibility and provides a better user experience.
Related Topics
- Selecting DOM elements — find the elements you need to label and focus.
- Modifying the document — set ARIA attributes and
alttext as you create elements. - Event handling in the DOM — add both
clickandkeydownhandlers for keyboard support. - Focusing: focus / blur — manage focus programmatically for modals and dynamic content.
Conclusion
Accessibility is a fundamental aspect of web development that ensures your content is usable by all people, regardless of their abilities. By creating accessible content, using techniques to make DOM manipulation accessible, and leveraging ARIA attributes, you can significantly improve the inclusivity and usability of your web applications. Implementing these practices not only helps meet legal standards but also enhances the overall user experience.