Back to Blog
Headshot of Isidora Brašančević

4 minutes read

Building accessible web apps: A developer’s perspective

Isidora Brašančević

Software Engineer

Making the web accessible means building interfaces for people with a variety of needs, not just meeting a checklist. As developers, we play a crucial role in making the web usable for people with disabilities, whether they rely on screen readers, keyboard navigation, or other assistive technologies.

This topic has gained even more attention in recent years, especially with the European Accessibility Act set to take full effect by 28 June 2025, requiring many digital products and services across the EU to meet the Web Content Accessibility Guidelines (WCAG).

Working with Next.js and modern component-based architectures has brought many accessibility challenges to light. Some are subtle, while others are more structural. In this post, we’ll share some common pitfalls, practical tips, and testing advice based on our hands-on experience.

Avoiding common pitfalls: Interactive element nesting

A common issue we’ve encountered is the improper nesting of interactive elements. For example, using a clickable card implemented as a <button>, and placing a second interactive button (like a share or favorite icon) inside it. This results in invalid HTML (<button> inside <button>), which frameworks like Next.js will flag as an error.

Here’s an example of what not to do:

<button onClick={handleCardClick}>
  <div className="card-content">Card content</div>
  <button onClick={handleFavoriteClick}>Favorite</button><br></button><br>

Trying to fix this by replacing the inner button with a <div> only adds new problems, since <div>s aren’t focusable or keyboard-operable by default.

The better approach is to avoid nesting and separate the interactive areas. If the card triggers navigation, wrap only the card content using Next.js’s next/link, or a regular <a> tag, and place the button outside:

<Link href={`/details/${item.id}`}>
  <div className="card-content">Card content</div>
</Link><br><button onClick={handleFavoriteClick} aria-label="Mark as favorite">
  Favorite
</button><br>

This keeps the HTML valid and the interactions accessible. Each element has a clear role and behaves correctly for both keyboard and screen reader users.

Automated tools help, but have their limits

Tools like Axe DevTools are useful for catching issues such as missing alt attributes, incorrect heading structures, or invalid ARIA roles. However, they don’t catch everything.

You’ll still need manual testing to uncover issues like:

  • Improper focus management, where users might lose track of their position after interacting with components like modals or dropdowns
  • Unintuitive keyboard interactions, where the tab order or expected shortcuts don’t match how users naturally navigate
  • Hidden interactive elements, such as invisible buttons or links that remain focusable or announced by screen readers
  • Missing keyboard shortcuts, where expected behaviors like pressing Escape to close a modal or using arrow keys to move through items aren’t supported

Manual testing tips that make a difference

Test with a screen reader

On macOS, you can activate VoiceOver using Cmd + F5, or through System Settings > Accessibility > VoiceOver. Navigate your site using the keyboard and listen to how content is announced. This helps identify poor labeling, missing context, or confusing focus flow.

Keyboard navigation

Navigate the entire site using only the keyboard. Make sure that:

  • Focus is visible at all times
  • All interactive elements are reachable
  • The tab order flows logicall

Modal dialogs

  • Trap focus inside the modal while it’s open
  • Allow users to dismiss the modal using the Escape key
  • Return focus to the triggering element after the modal closes

Tabs and tab panels

Allow users to switch tabs with arrow keys instead of forcing them to tab through all content in a tab panel to reach the next tab. Follow the ARIA tab pattern where appropriate.

Carousels and galleries

Support left and right arrow key navigation alongside standard keyboard navigation. This allows users to move through items more efficiently, especially when there are many elements to navigate.

These kinds of enhancements go beyond basic compliance. They significantly improve usability and are often missed by automated tools.

Don’t forget the fundamentals

Accessibility starts with good HTML. Some basic but critical practices include:

  • Always use meaningful alt text for images. In some cases, omitting the alt attribute entirely (so screen readers skip the image) is better than providing a misleading or generic one. Here are some examples of good and bad alt usage:
<!-- Bad: Missing alt --><br><img src="/images/coastline.jpg"><br><br><!-- Bad: Unhelpful description --><br><img src="/images/coastline.jpg" alt="Nice view"><br><br><!-- Good: Clear and concise --><br><img src="/images/coastline.jpg" alt="Group of white buildings on a hill overlooking the coastline and ocean"><br>

For decorative images that don’t provide meaningful information, it’s better to use an empty alt attribute so screen readers skip them:

<!-- Good: Decorative image with empty alt --><br><img src="/images/decorative-pattern.svg" alt=""><br>
  • Use native HTML elements for interactivity. For example, use <button> instead of a <div> with an onClick, and <a> or Next.js <Link> for navigation. Use form elements like <input>, <label>, <select>, and <textarea> where appropriate.
<!-- Bad: Non-semantic element used for a button --><br><div onClick={handleClick} class="btn">Submit</div><br><br><!-- Good: Proper semantic button element --><br><button onClick={handleClick}>Submit</button><br>
  • Make sure every interactive element is accessible by screen reader and keyboard. Buttons, links, icons, and other controls should either have visible text or an aria-label so their purpose is clear to assistive technologies. They should also be reachable via keyboard navigation, which can be managed using semantic HTML or by applying tabindex when needed.
  • Follow semantic structure. Use headings in logical order (<h1> to <h6>) and proper landmarks like <main>, <nav>, <header>, and <section> to give assistive technologies meaningful context.
  • Ensure sufficient color contrast and visible focus indicators. This supports users with visual impairments and those navigating via keyboard.

Conclusion

Accessibility shouldn’t be treated as a final step. It works best when integrated into the process from the beginning. The earlier you build accessibility into your components, the easier it becomes to maintain and scale.

Real accessibility means more than just meeting technical criteria. It requires testing how people actually interact with your site. Tools can help, but nothing replaces manual testing and taking the time to see things from the user’s perspective.

By focusing on semantics, interactivity, and thoughtful keyboard behavior, we can build applications that are more inclusive, robust, and user-friendly for everyone.

Headshot of Isidora Brašančević

Isidora Brašančević

Software Engineer

Isidora is a frontend software engineer with experience in building responsive and accessible web applications using React and Next.js. She enjoys shaping ideas into clean, maintainable code and is always eager to learn, improve, and take on new challenges. Her curiosity and attention to detail drive her to create thoughtful user experiences and grow continuously as a developer.

Related posts.