Building Accessible Web Apps: A Practical Guide for Busy Developers
I used to treat accessibility as a nice-to-have — something I would "get around to" after shipping features. Then I watched a blind developer try to use a tool I built. They could not navigate past the first screen. The form had no labels, the buttons had no accessible names, and the custom dropdown was completely invisible to their screen reader.
That experience changed how I build software. Accessibility is not a feature — it is a baseline requirement, like making sure your site loads without JavaScript errors. Here is how to build it in from the start without slowing down your development.
The 80/20 of Accessibility
You do not need to memorize the entire WCAG specification. These practices cover the vast majority of accessibility issues:
Semantic HTML First
Use the right HTML element for the job. A button that submits a form? Use a button element, not a div with an onClick handler. A navigation menu? Use a nav element with a list of links. A page heading? Use h1 through h6 in order.
Semantic HTML gives you accessibility for free. A button element is focusable, responds to Enter and Space keys, and announces itself as a button to screen readers. A div with role="button" requires you to manually implement all of that — and you will miss something.
The rule is simple: if an HTML element exists for what you are building, use it. Only reach for ARIA attributes when no semantic element fits.
Labels on Everything
Every form input needs a label. Every button needs accessible text. Every image needs alt text (or alt="" for decorative images). This alone fixes 40% of accessibility issues.
For inputs: use a label element with htmlFor pointing to the input's id. Placeholder text is not a label — it disappears when the user starts typing and has insufficient contrast in most designs.
For buttons with icons only: add aria-label or visually hidden text. A button with just a magnifying glass icon needs aria-label="Search" so screen readers announce "Search button" instead of just "button."
For images: alt text should describe the image's purpose, not its appearance. "Screenshot showing the JSON Formatter output with syntax highlighting" is better than "a colorful code block."
Keyboard Navigation
Every interactive element must be reachable and operable with a keyboard alone. Tab moves focus forward. Shift+Tab moves focus backward. Enter and Space activate buttons and links. Arrow keys navigate within components (tabs, dropdowns, menus).
The most common failure: custom components that only work with mouse clicks. If you build a custom dropdown, it needs to respond to Arrow Down (open and navigate options), Enter (select), and Escape (close). If you build a modal, it needs to trap focus inside and close on Escape.
Test by unplugging your mouse (or just not touching your trackpad) and navigating your entire application with the keyboard alone. Every page, every form, every interactive element. You will find issues immediately.
Color and Contrast
Text must have sufficient contrast against its background. WCAG requires 4.5:1 for normal text and 3:1 for large text (18px+ or 14px+ bold). Check with the browser's built-in contrast checker in DevTools.
Never convey information through color alone. Error states need an icon or text in addition to red coloring. Success states need more than green. Required fields need an asterisk or text, not just a red border.
Focus Indicators
Never set outline: none without providing an alternative focus indicator. When keyboard users tab through your page, they need to see which element is currently focused. The default browser outline is fine — if your design team insists on removing it, replace it with a custom focus ring that is equally visible.
Our approach: we use Tailwind's focus-visible utility to show focus rings only for keyboard navigation, not for mouse clicks. This satisfies both designers and accessibility requirements.
Component-Level Patterns
Modals and Dialogs
When a modal opens: move focus to the first focusable element inside. Trap focus inside (Tab should cycle within the modal, not escape to the page behind). Close on Escape. Return focus to the trigger element when closed. Add aria-modal="true" and role="dialog" with an aria-labelledby pointing to the dialog title.
Tabs
Use role="tablist" on the container, role="tab" on each tab, and role="tabpanel" on each panel. Arrow keys navigate between tabs. The active tab has aria-selected="true". The active panel has tabindex="0" so it is focusable. Hidden panels have hidden or aria-hidden="true".
Toast Notifications
Use role="alert" or aria-live="polite" so screen readers announce the notification without interrupting the current task. Toasts should not auto-dismiss too quickly — 5 seconds minimum, and provide a way to dismiss manually.
Data Tables
Use proper table markup (table, thead, tbody, th, td). Add scope="col" or scope="row" to header cells. For complex tables with merged cells, use aria-describedby to reference a caption explaining the table structure.
Testing Accessibility
Automated Testing
Run axe-core in your CI pipeline. It catches about 30% of accessibility issues automatically: missing alt text, insufficient contrast, missing form labels, invalid ARIA attributes. We run it as a Jest test that renders each page and checks for violations.
Manual Testing
Automated tools miss interaction issues. Spend 10 minutes per feature testing with keyboard only and with a screen reader. On macOS, VoiceOver is built in (Command+F5). On Windows, NVDA is free.
The first time you use a screen reader on your own site, you will find issues. That is normal. Fix them, and test again.
User Testing
If possible, include users with disabilities in your user testing. They will find issues that no automated tool or sighted tester would catch — confusing announcements, illogical tab orders, missing context that sighted users get from visual layout.
The Business Case
Accessibility is legally required in many jurisdictions (ADA in the US, EAA in the EU). But beyond compliance, it is good business:
Accessible sites work better for everyone. Keyboard shortcuts help power users. High contrast helps users in bright sunlight. Captions help users in noisy environments. Good heading structure helps users who skim.
Accessible sites rank better in search engines. Semantic HTML, alt text, and heading structure are all SEO factors. Building for accessibility improves your organic traffic.
The cost of retrofitting accessibility is 10x higher than building it in from the start. Every component you build without accessibility is debt you will pay later — with interest.
Our Approach at AIDToolStack
Every tool page on our platform follows these principles. Our tool components use semantic HTML for structure, aria-label on icon-only buttons, keyboard shortcuts for power users, and high-contrast themes. The skip-to-content link at the top of every page lets keyboard users jump past the navigation. Our command palette (Cmd+K) is fully keyboard navigable and announces results to screen readers.
Accessibility is not a separate workstream for us — it is how we build. Every PR gets a quick keyboard navigation test, and axe-core runs in CI. It adds maybe 5% to development time and saves us from accumulating accessibility debt that would take weeks to pay down later.
Written by AIDToolStack Editorial
The AIDToolStack editorial team reviews developer tools, AI products, and MCP servers with hands-on testing and honest assessments. We use the tools we review every day in production.
References & Further Reading
Related Posts
Sponsor Our Newsletter
Reach thousands of developers who are actively evaluating AI tools, MCP servers, and dev infrastructure. Our weekly newsletter goes to engaged technical decision-makers.
All sponsored content is clearly labeled per our editorial policy.