DEV Community

Goodwill Ads Agency
Goodwill Ads Agency

Posted on

Building Accessible Web Components: A Developer's Guide to Inclusive Design โ™ฟ

Why Accessibility Matters in 2025 ๐ŸŒ
As developers, we shape how billions interact with the digital world. Over 1.3 billion people worldwide live with disabilities, yet many web applications inadvertently exclude them. Building accessible components isn't just complianceโ€”it's about creating inclusive experiences that reflect values of equality and social responsibility.
At Goodwill Ads Agency, we've seen how accessible design serves users with disabilities while improving usability for everyone, leading to better business outcomes and stronger brand reputation.
The Business Case ๐Ÿ“Š

$8 trillion annual disposable income from people with disabilities globally
71% of users with disabilities leave inaccessible websites
Accessible sites see 28% higher revenue and 2x more visits
SEO benefits - semantic HTML improves search indexing

Learn more about how accessible design impacts marketing performance in our guide.
WCAG 2.1 Fundamentals (POUR) ๐ŸŽฏ

  1. Perceivable ๐Ÿ‘€ - Provide text alternatives, captions, sufficient contrast
  2. Operable โŒจ๏ธ - Keyboard accessible, adequate time, no seizures
  3. Understandable ๐Ÿง  - Readable text, predictable operation
  4. Robust ๐Ÿ’ช - Compatible with assistive technologies Building an Accessible Button Component ๐Ÿ”˜ HTML Structure html ๐Ÿ“Š View Analytics Opens detailed analytics dashboard CSS with Accessibility Features css.custom-button { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.75rem 1.5rem; min-height: 44px; /* Touch target size */ min-width: 44px; font-size: 1rem; border: 2px solid #3b82f6; border-radius: 0.375rem; background-color: #3b82f6; color: white; cursor: pointer; transition: all 0.2s ease-in-out; }

/* Focus states for keyboard navigation */
.custom-button:focus-visible {
outline: 3px solid #fbbf24;
outline-offset: 2px;
box-shadow: 0 0 0 3px rgba(251, 191, 36, 0.3);
}

/* High contrast mode support */
@media (prefers-contrast: high) {
.custom-button {
border-width: 3px;
font-weight: 700;
}
}

/* Reduced motion support */
@media (prefers-reduced-motion: reduce) {
.custom-button {
transition: none;
}
}

/* Screen reader only content */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
JavaScript Enhancement
javascriptclass AccessibleButton {
constructor(element) {
this.button = element;
this.init();
}

init() {
this.button.addEventListener('keydown', this.handleKeyDown.bind(this));
this.button.addEventListener('click', this.handleClick.bind(this));
this.createLiveRegion();
}

handleKeyDown(event) {
if (event.key === ' ' || event.key === 'Enter') {
event.preventDefault();
this.handleClick(event);
}
}

handleClick(event) {
const isPressed = this.button.getAttribute('aria-pressed') === 'true';

if (this.button.hasAttribute('aria-pressed')) {
  this.button.setAttribute('aria-pressed', !isPressed);
  this.announceStateChange(!isPressed ? 'activated' : 'deactivated');
}
Enter fullscreen mode Exit fullscreen mode

}

announceStateChange(state) {
if (this.liveRegion) {
this.liveRegion.textContent = Button ${state};
setTimeout(() => this.liveRegion.textContent = '', 1000);
}
}

createLiveRegion() {
this.liveRegion = document.createElement('div');
this.liveRegion.setAttribute('aria-live', 'polite');
this.liveRegion.className = 'sr-only';
document.body.appendChild(this.liveRegion);
}
}

// Initialize buttons
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.custom-button')
.forEach(button => new AccessibleButton(button));
});
Accessible Modal Dialog ๐ŸชŸ
HTML Structure
html
๐Ÿ“Š Open Analytics

  <h2 id="modal-title">Analytics Dashboard</h2>
  โŒ


  <p>View campaign analytics and performance metrics</p>
Enter fullscreen mode Exit fullscreen mode

Modal JavaScript
javascriptclass AccessibleModal {
constructor(modalId) {
this.modal = document.getElementById(modalId);
this.trigger = document.querySelector([data-target="${modalId}"]);
this.closeButton = this.modal.querySelector('.modal-close');
this.previouslyFocusedElement = null;
this.init();
}

init() {
this.trigger.addEventListener('click', this.open.bind(this));
this.closeButton.addEventListener('click', this.close.bind(this));
this.modal.addEventListener('keydown', this.handleKeyDown.bind(this));
}

open() {
this.previouslyFocusedElement = document.activeElement;
this.modal.setAttribute('aria-hidden', 'false');
document.body.style.overflow = 'hidden';

// Focus first focusable element
const focusable = this.modal.querySelectorAll(
  'button:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
);
if (focusable.length > 0) focusable[0].focus();
Enter fullscreen mode Exit fullscreen mode

}

close() {
this.modal.setAttribute('aria-hidden', 'true');
document.body.style.overflow = '';
if (this.previouslyFocusedElement) {
this.previouslyFocusedElement.focus();
}
}

handleKeyDown(event) {
if (event.key === 'Escape') {
this.close();
} else if (event.key === 'Tab') {
this.trapFocus(event);
}
}

trapFocus(event) {
const focusableElements = this.modal.querySelectorAll(
'button:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
);
const firstFocusable = focusableElements[0];
const lastFocusable = focusableElements[focusableElements.length - 1];

if (event.shiftKey && document.activeElement === firstFocusable) {
  event.preventDefault();
  lastFocusable.focus();
} else if (!event.shiftKey && document.activeElement === lastFocusable) {
  event.preventDefault();
  firstFocusable.focus();
}
Enter fullscreen mode Exit fullscreen mode

}
}

// Initialize modal
document.addEventListener('DOMContentLoaded', () => {
new AccessibleModal('analytics-modal');
});
Form Accessibility Best Practices ๐Ÿ“
Enhanced Form HTML
html




Campaign Name *

type="text"
id="campaign-name"
name="campaignName"
required
aria-describedby="campaign-name-help campaign-name-error"
aria-invalid="false"
/>

Choose a memorable name for your campaign



Target Audiences


Gen Z (18-27)



Millennials (28-43)

Create Campaign


Testing Your Components ๐Ÿงช
Essential Testing Checklist โœ…
Keyboard Navigation:

All interactive elements reachable via Tab
Logical tab order
Visible focus indicators
Escape closes modals/dropdowns

Screen Reader Testing:

Content announced correctly
Interactive elements have proper labels
State changes announced
Error messages announced immediately

Visual Testing:

4.5:1 contrast ratio for text
UI works at 200% zoom
Mobile responsiveness
High contrast mode support

Automated Testing
javascript// Basic accessibility test with Playwright
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';

test('should not have accessibility violations', async ({ page }) => {
await page.goto('/your-page');

const accessibilityScanResults = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa'])
.analyze();

expect(accessibilityScanResults.violations).toEqual([]);
});
Essential Tools ๐Ÿ”ง
Browser Extensions:

axe DevTools - Automated scanning
WAVE - Visual accessibility evaluation
Lighthouse - Built-in accessibility audit

Screen Readers:

NVDA (Windows) - Free
VoiceOver (macOS) - Built-in
JAWS (Windows) - Professional

Ready to implement accessible design in your projects? Check out our comprehensive accessibility services for expert guidance.
Conclusion: Building for Everyone ๐ŸŒŸ
Accessible web components benefit everyoneโ€”not just users with disabilities. They improve SEO, enhance mobile experiences, and create more robust, semantic code. As developers working in an industry focused on social good, we have a responsibility to ensure our digital products welcome all users.
Start small: implement proper focus management, add ARIA labels, ensure keyboard navigation works. Test with real users and assistive technologies. Remember, accessibility is not a featureโ€”it's a fundamental aspect of good development.
Key Takeaways:

Use semantic HTML as your foundation
Implement proper ARIA labels and roles
Ensure keyboard navigation works throughout
Test with actual assistive technologies
Consider accessibility from the design phase

For more insights on inclusive development and purpose-driven technology, follow Goodwill Ads Agency and explore our developer resources.

Tags: #webdev #a11y #accessibility #javascript #html #css #inclusivedesign #frontend

Top comments (0)