DE
- Industries
- Finance
Nearshore software development for finance—secure, scalable, and compliant solutions for banking, payments, and APIs.
- Retail
Retail software development services—e-commerce, POS, logistics, and AI-driven personalization from nearshore engineering teams.
- Manufacturing
Nearshore manufacturing software development—ERP systems, IoT platforms, and automation tools to optimize industrial operations.
- Finance
- What we do
- Services
- Technologies
- Collaboration models
Explore collaboration models customized to your specific needs: Complete nearshoring teams, Local heroes from partners with the nearshoring team, or Mixed tech teams with partners.
- Way of work
Through close collaboration with your business, we create customized solutions aligned with your specific requirements, resulting in sustainable outcomes.
- About Us
- Who we are
We are a full-service nearshoring provider for digital software products, uniquely positioned as a high-quality partner with native-speaking local experts, perfectly aligned with your business needs.
- Meet our team
ProductDock’s experienced team proficient in modern technologies and tools, boasts 15 years of successful projects, collaborating with prominent companies.
- Our locations
We are ProductDock, a full-service nearshoring provider for digital software products, headquartered in Berlin, with engineering hubs in Lisbon, Novi Sad, Banja Luka, and Doboj.
- Why nearshoring
Elevate your business efficiently with our premium full-service software development services that blend nearshore and local expertise to support you throughout your digital product journey.
- Who we are
- Our work
- Career
- Life at ProductDock
We’re all about fostering teamwork, creativity, and empowerment within our team of over 120 incredibly talented experts in modern technologies.
- Open positions
Do you enjoy working on exciting projects and feel rewarded when those efforts are successful? If so, we’d like you to join our team.
- Candidate info guide
How we choose our crew members? We think of you as a member of our crew. We are happy to share our process with you!
- Life at ProductDock
- Newsroom
- News
Stay engaged with our most recent updates and releases, ensuring you are always up-to-date with the latest developments in the dynamic world of ProductDock.
- Events
Expand your expertise through networking with like-minded individuals and engaging in knowledge-sharing sessions at our upcoming events.
- News
- Blog
- Get in touch

11. Sep 2025 •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>
</button>
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>
<button onClick={handleFavoriteClick} aria-label="Mark as favorite">
Favorite
</button>
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 logically
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 thealt
attribute entirely (so screen readers skip the image) is better than providing a misleading or generic one. Here are some examples of good and badalt
usage:
<!-- Bad: Missing alt -->
<img src="/images/coastline.jpg">
<!-- Bad: Unhelpful description -->
<img src="/images/coastline.jpg" alt="Nice view">
<!-- Good: Clear and concise -->
<img src="/images/coastline.jpg" alt="Group of white buildings on a hill overlooking the coastline and ocean">
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 -->
<img src="/images/decorative-pattern.svg" alt="">
- 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 -->
<div onClick={handleClick} class="btn">Submit</div>
<!-- Good: Proper semantic button element -->
<button onClick={handleClick}>Submit</button>
- 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 applyingtabindex
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.
Tags:Skip tags
Isidora Brašančević
Software EngineerIsidora 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.