
Accessibility in Code: The Most Common Accessibility Errors in Technical Development

Accessibility issues on the web are rarely isolated incidents. In practice, they are predominantly recurring implementation errors that are reproduced across projects, frameworks, and components. This recurrence indicates that their root causes lie in fundamental technical patterns rather than in exceptional, case-specific circumstances.
The WebAIM Million Report 2025[1], one of the most comprehensive studies on web accessibility, clearly illustrates the scale of this problem: 94.8% of analyzed homepages contained at least one detectable WCAG violation, with an average of more than 50 identifiable errors per page. At the same time, WebAIM emphasizes that automated testing captures only a limited subset of existing barriers and cannot provide a comprehensive assessment of accessibility. Many critical aspects, particularly interaction patterns, semantic correctness, focus management, and overall usability, can only be reliably evaluated through manual inspection and user testing.[2]
From a technical perspective, these issues frequently originate in fundamental implementation decisions. Accessibility is often mistakenly treated as a post hoc refinement rather than as an integral component of system architecture.
What Constitutes a Technical Accessibility Error
A technical accessibility error refers to a deficiency in code implementation or in the behavior of a user interface that results in content or functionality being inaccessible, or only partially accessible, to certain user groups. This particularly affects the use of assistive technologies (e.g., screen readers), keyboard interaction, adaptability of presentation (e.g., zoom or reflow), as well as non-visual or alternative navigation methods.
The Web Content Accessibility Guidelines (WCAG) define accessibility through four core principles: content must be Perceivable, Operable, Understandable, and Robust (POUR)[4]. Technical accessibility errors occur whenever one or more of these requirements are not met due to implementation shortcomings.
This article focuses specifically on technical issues that developers can directly identify and resolve within code, component design, or interaction logic.
Incorrect Semantics and Page Structure
A fundamental requirement for accessible web interfaces is a semantically correct page structure. What matters is not only how a page appears visually, but whether its structure is programmatically determinable. According to WCAG success criterion 1.3.1 (Info and Relationships), information, structure, and relationships conveyed visually must also be available in the underlying code, so they can be interpreted correctly by browsers and assistive technologies. This includes elements such as headings, lists, form relationships, table structures, and page regions.
As a result, a page may appear visually well-organized while still being difficult or impossible to interpret for assistive technologies if semantic HTML elements are missing or misused.[5]
A common issue is the overuse of generic containers such as div and span, even when more meaningful semantic elements like header, nav, main, footer, section, article, h1–h6, ul, ol, button, or structured form elements are available. Semantic HTML elements are specifically designed to express the meaning and structure of content, rather than merely its visual presentation.[6]
Headings and landmarks are particularly important in this context. Headings define the logical hierarchy of a page and enable structured navigation, for example via screen readers or reader modes. Landmark elements such as main, nav, header, and footer identify key regions of a page and allow users to navigate directly to them.[7]
Common issues include visually styled text that is not marked up as actual headings, skipped or inconsistent heading hierarchies, lists that are presented visually without using ul or ol, interactive elements implemented as clickable divs instead of proper buttons, and missing or improperly labeled landmarks.
The fundamental principle is straightforward: if a structure is relevant for understanding, navigation, or interaction, it must be represented in the markup.
Common Mistakes: Code Exampleshtml
<!--
1. Generic containers instead of semantic structure
Problem: Assistive technologies cannot identify a clear page structure; navigation via landmarks and structural elements is not possible.
-->
<!-- Bad -->
<div class="header">
<div class="logo">Shop</div>
<div class="menu">
<span>Products</span>
<span>Contact</span>
</div>
</div>
<div class="content">
<div class="title">Our Products</div>
<div class="subtitle">New Collection</div>
<div class="product-list">
<div>Backpack</div>
<div>Sneakers</div>
<div>Jacket</div>
</div>
</div>
<div class="footer">
© 2026 Shop
</div>
<!-- Better -->
<header>
<a href="/" aria-label="Homepage">Shop</a>
<nav aria-label="Main navigation">
<ul>
<li><a href="/products">Products</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
</header>
<main>
<h1>Our Products</h1>
<section aria-labelledby="new-collection-heading">
<h2 id="new-collection-heading">New Collection</h2>
<ul>
<li>Backpack</li>
<li>Sneakers</li>
<li>Jacket</li>
</ul>
</section>
</main>
<footer>
<p>© 2026 Shop</p>
</footer>
<!--
2. Visual headings without semantic markup
Problem: Screen readers cannot detect a heading structure; navigation by headings is limited or impossible.
-->
<!-- Bad -->
<p class="headline">Shipping Information</p>
<p>We deliver within 3–5 business days.</p>
<p class="subheadline">Shipping Costs</p>
<p>Shipping costs €4.90.</p>
<!-- Better -->
<section aria-labelledby="shipping-heading">
<h2 id="shipping-heading">Shipping Information</h2>
<p>We deliver within 3–5 business days.</p>
<h3>Shipping Costs</h3>
<p>Shipping costs €4.90.</p>
</section>
<!--
3. Inconsistent or skipped heading hierarchy
Problem: The logical document structure is disrupted; users have difficulty understanding and navigating content.
-->
<!-- Bad -->
<main>
<h1>Help & Support</h1>
<h4>Contact Us</h4>
<p>Our support team will be happy to help.</p>
</main>
<!-- Better -->
<main>
<h1>Help & Support</h1>
<section>
<h2>Contact Us</h2>
<p>Our support team will be happy to help.</p>
</section>
</main>
<!--
4. Missing semantic elements for interaction
Problem: Interactive elements without proper semantics are not keyboard accessible and are not recognized correctly by assistive technologies.
-->
<!-- Bad -->
<div class="button" onclick="openMenu()">
Open menu
</div>
<!-- Better -->
<button type="button" onclick="openMenu()">
Open menu
</button>
<!--
5. Visual lists without semantic list structure
Problem: Related content is not recognized as a group; screen readers do not announce list semantics.
-->
<!-- Bad -->
<div class="features">
<div>✓ Free shipping</div>
<div>✓ 30-day returns</div>
<div>✓ Secure payment</div>
</div>
<!-- Better -->
<ul>
<li>Free shipping</li>
<li>30-day returns</li>
<li>Secure payment</li>
</ul>Missing Names, Labels, and Alternative Text
Another major category of accessibility issues involves missing or unclear accessible names. Interactive elements require a programmatically determinable name, images must include appropriate alternative text, and form controls need clearly associated labels. These elements are essential for assistive technologies to correctly identify, interpret, and convey content.
WCAG success criterion 1.1.1 (Non-text Content)[8] requires that all non-text content be provided with suitable text alternatives. Additionally, 4.1.2 (Name, Role, Value)[9] mandates that user interface components expose a programmatically determinable name. For forms, 3.3.2 (Labels or Instructions)[10] specifies that input fields must be clearly labeled or accompanied by understandable instructions.
An accessible name can be derived from multiple sources, including visible text, label elements, alternative text, or ARIA attributes such as aria-label and aria-labelledby. It is critical that this name is unambiguous, meaningful, and consistent with the visible user interface.
Common issues arise when this association is missing or insufficient. These include input fields without labels, placeholders used as the sole form of labeling, ambiguous group labels applied to multiple fields, and icon-only buttons without an accessible name. Similarly problematic are links with non-descriptive text, decorative images lacking alt="", and meaningful images without appropriate alternative descriptions.
Another frequent issue is a mismatch between the visible label and the accessible name. When these diverge significantly, it creates inconsistencies in interaction, particularly for screen reader users.[11]
The fundamental principle is clear: every functional element and every non-decorative piece of content must have a clear, understandable, and programmatically available name. Only then can content be reliably accessed and used across different modes of interaction and presentation.
Common Mistakes: Code Exampleshtml
<!--
1. Input field without a label
Problem: Screen reader users cannot determine what information is expected; the field is not uniquely identifiable.
-->
<!-- Bad -->
<input type="text" name="email">
<!-- Better -->
<label for="email">Email address</label>
<input type="email" id="email" name="email" autocomplete="email">
<!--
2. Placeholder used as the only label
Problem: The placeholder disappears during input and does not provide a reliable accessible name.
-->
<!-- Bad -->
<input type="text" placeholder="Email address">
<!-- Better -->
<label for="email2">Email address</label>
<input
type="email"
id="email2"
name="email"
placeholder="name@example.com"
autocomplete="email"
>
<!--
3. Ambiguous group label for multiple fields
Problem: Multiple input fields are not individually labeled, making their purpose unclear.
-->
<!-- Bad -->
<label>Name:</label>
<input type="text" name="firstName">
<input type="text" name="lastName">
<!-- Better -->
<fieldset>
<legend>Name</legend>
<label for="firstName">First name</label>
<input type="text" id="firstName" name="firstName" autocomplete="given-name">
<label for="lastName">Last name</label>
<input type="text" id="lastName" name="lastName" autocomplete="family-name">
</fieldset>
<!--
4. Icon-only button without an accessible name
Problem: Screen readers cannot determine the purpose of the button.
-->
<!-- Bad -->
<button>
<svg><!-- icon --></svg>
</button>
<!-- Better -->
<button type="button" aria-label="Search">
<svg aria-hidden="true" focusable="false"><!-- icon --></svg>
</button>
<!--
5. Link without descriptive text
Problem: The purpose of the link is not clear out of context.
-->
<!-- Bad -->
<a href="/contact">Click here</a>
<!-- Better -->
<a href="/contact">Contact us</a>
<!--
6. Decorative image without empty alt attribute
Problem: Screen readers may announce unnecessary or confusing information.
-->
<!-- Bad -->
<img src="divider.png">
<!-- Better -->
<img src="divider.png" alt="">
<!--
7. Meaningful image without appropriate alternative text
Problem: Important information is lost for users who cannot see the image.
-->
<!-- Bad -->
<img src="chart.png" alt="Image">
<!-- Better -->
<img src="chart.png" alt="Revenue increased by 20% in 2025">
<!--
8. Mismatch between visible label and accessible name
Problem: Inconsistent naming creates confusion for screen reader users.
-->
<!-- Bad -->
<button aria-label="Submit form">Buy now</button>
<!-- Better -->
<button>Buy now</button>
<!-- Alternative (extended but consistent) -->
<button aria-label="Buy now – complete purchase">
Buy now
</button>Keyboard Accessibility and Focus Management
A common misconception in practice is that an interface is considered keyboard-accessible simply because some elements can be reached using the Tab key. In reality, WCAG success criterion 2.1.1 (Keyboard) [12]requires that all functionality available via mouse interaction must also be fully operable through the keyboard. In addition, focus must not become trapped unintentionally, as specified in 2.1.2 (No Keyboard Trap)[13].
Keyboard accessibility extends beyond mere reachability: interactions must be fully executable, and focus must move through the interface in a predictable, logical, and consistent manner.
Typical issues arise when interactive elements are not properly implemented. These include clickable div or span elements without keyboard support, custom components such as dropdowns or accordions that respond only to mouse interaction, and removed or insufficient focus indicators. Other common problems include illogical tab sequences, unexpected focus shifts, and missing focus management in more complex components such as dialogs, all of which significantly hinder usability.
Another critical aspect is focus visibility. According to WCAG 2.4.7 (Focus Visible)[14], it must always be clear which element currently has focus. If the focus indicator is removed or visually obscured, for example, by fixed UI elements, users lose orientation, particularly those relying on keyboard navigation or assistive technologies.
Focus is not merely an implementation detail; it is the central point of user interaction. It determines where input is directed and how users navigate through an interface. When focus becomes invisible, inconsistent, or unpredictable, the usability of the interface is immediately compromised.
Common Mistakes: Code Exampleshtml
<!--
1. Clickable div/span without keyboard support
Problem: The element cannot be reliably reached or activated by keyboard; it is not a native interactive component.
-->
<!-- Bad -->
<div onclick="openMenu()">
Open menu
</div>
<!-- Better -->
<button type="button" onclick="openMenu()">
Open menu
</button>
<!--
2. Mouse-only interactive component, e.g. dropdown
Problem: Keyboard users cannot reliably open, navigate, or operate the component.
-->
<!-- Bad -->
<div class="dropdown" onclick="toggleDropdown()">
Options
<div class="menu">
<div>Profile</div>
<div>Settings</div>
</div>
</div>
<!-- Better -->
<button
type="button"
aria-haspopup="true"
aria-expanded="false"
aria-controls="options-menu"
onclick="toggleDropdown()"
>
Options
</button>
<ul id="options-menu" hidden>
<li><a href="/profile">Profile</a></li>
<li><a href="/settings">Settings</a></li>
</ul>
<!--
3. Removed focus indicator
Problem: Users cannot see which element currently has focus.
-->
<!-- Bad -->
<style>
:focus {
outline: none;
}
</style>
<button>Save</button>
<!-- Better -->
<style>
:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}
</style>
<button>Save</button>
<!--
4. Illogical tab order
Problem: Focus does not follow the visual and logical reading order; navigation becomes unpredictable.
-->
<!-- Bad -->
<input type="text" placeholder="Name" tabindex="3">
<input type="email" placeholder="Email" tabindex="1">
<button tabindex="2">Submit</button>
<!-- Better -->
<input type="text" placeholder="Name">
<input type="email" placeholder="Email">
<button>Submit</button>
<!--
5. Unexpected focus movement
Problem: Users lose control of their current position; the context changes without explicit intent.
-->
<!-- Bad -->
<input type="text" oninput="document.getElementById('next').focus()">
<input type="text" id="next">
<!-- Better -->
<input type="text">
<input type="text" id="next">
<!-- Focus remains under the user's control; no forced focus movement. -->
<!--
6. Modal without proper focus management
Problem: Focus may remain behind the modal, move outside it, or become lost; keyboard navigation breaks.
-->
<!-- Bad -->
<div class="modal">
<p>Dialog content</p>
<button onclick="closeModal()">Close</button>
</div>
<!-- Better -->
<div role="dialog" aria-modal="true" aria-labelledby="modal-title">
<h2 id="modal-title">Dialog</h2>
<p>Dialog content</p>
<button type="button" autofocus onclick="closeModal()">Close</button>
</div>
<!-- When opened, focus is moved into the dialog and returned to the triggering element when closed. -->
<!--
7. Fixed elements obscure focused content
Problem: Focused elements may be visually hidden behind fixed or sticky UI, such as headers.
-->
<!-- Bad -->
<style>
header {
position: fixed;
top: 0;
height: 80px;
}
</style>
<a href="#main">Skip to content</a>
<main id="main">
<h1>Content</h1>
</main>
<!-- Better -->
<style>
header {
position: fixed;
top: 0;
height: 80px;
}
#main {
scroll-margin-top: 100px;
}
</style>
<a href="#main">Skip to content</a>
<main id="main" tabindex="-1">
<h1>Content</h1>
</main>Custom Widgets and ARIA
Native HTML elements such as button, input, or select inherently provide semantics, keyboard operability, focus behavior, and state communication. When these elements are replaced with custom widgets, all of these aspects must be explicitly reimplemented.
WCAG success criterion 4.1.2 (Name, Role, Value)[9] requires that all interactive components expose a programmatically determinable name, role, and, where applicable, state. These properties are essential for assistive technologies to accurately convey both the function and the current status of an element.
At the same time, the WAI-ARIA Authoring Practices emphasize a fundamental principle: “No ARIA is better than bad ARIA.”[15] Semantic HTML should always be preferred when suitable native elements are available, as they inherently provide correct behavior and accessibility support.
The guiding principle is clear: a role is a promise. If an element is assigned role="button", it must behave like a button in all respects—including keyboard interaction (e.g., activation via Enter or Space), focusability, and both visual and programmatic state indication.
Common issues arise when these requirements are only partially implemented. These include roles without corresponding interaction logic, missing or uncommunicated states (e.g., absent aria-expanded attributes), dialogs that lack true modality or proper focus management, and complex widgets that fail to provide consistent keyboard navigation.
A particularly critical error is the use of aria-hidden="true" on focusable elements. This attribute removes content from the accessibility tree without affecting its visual presence, creating a discrepancy between what is visible and what is perceivable by assistive technologies. As noted by MDN, aria-hidden should not be applied to interactive or focusable elements[16].
The overarching recommendation is therefore: native HTML elements should always be used whenever possible. ARIA should only be applied when native semantics are insufficient and even then, it must be implemented comprehensively and correctly.
Common Mistakes: Code Exampleshtml
<!--
1. Role without corresponding behavior (role="button" without proper interaction)
Problem: A role promises behavior. If that behavior is not implemented, keyboard operability and user expectations are violated.
-->
<!-- Bad -->
<div role="button" onclick="save()">
Save
</div>
<!-- Better -->
<button type="button" onclick="save()">
Save
</button>
<!-- Alternative (only if a native button is not possible) -->
<div
role="button"
tabindex="0"
onclick="save()"
onkeydown="if (event.key === 'Enter' || event.key === ' ') save()"
>
Save
</div>
<!--
2. Missing state communication, e.g. toggle button
Problem: Screen reader users cannot determine whether a control is expanded, collapsed, active, or inactive.
-->
<!-- Bad -->
<div role="button" onclick="toggleMenu()">
Menu
</div>
<!-- Better -->
<button
type="button"
aria-expanded="false"
aria-controls="menu"
onclick="toggleMenu()"
>
Menu
</button>
<ul id="menu" hidden>
<li><a href="/profile">Profile</a></li>
<li><a href="/settings">Settings</a></li>
</ul>
<!--
3. Dialog without true modality
Problem: Focus is not constrained to the dialog, and users may continue interacting with background content.
-->
<!-- Bad -->
<div class="dialog">
<p>Confirm?</p>
<button>OK</button>
</div>
<!-- Better -->
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
<h2 id="dialog-title">Confirm</h2>
<p>Do you want to continue?</p>
<button type="button" autofocus>OK</button>
<button type="button">Cancel</button>
</div>
<!-- Focus must move into the dialog when it opens and return to the triggering element when it closes. -->
<!--
4. Complex widget without correct focus behavior, e.g. tabs
Problem: Users cannot navigate predictably with the keyboard, and focus is not managed according to the component pattern.
-->
<!-- Bad -->
<div class="tabs">
<div onclick="showTab(1)">Tab 1</div>
<div onclick="showTab(2)">Tab 2</div>
</div>
<!-- Better -->
<div role="tablist" aria-label="Account settings">
<button
type="button"
role="tab"
aria-selected="true"
aria-controls="panel1"
id="tab1"
>
Tab 1
</button>
<button
type="button"
role="tab"
aria-selected="false"
aria-controls="panel2"
id="tab2"
tabindex="-1"
>
Tab 2
</button>
</div>
<div id="panel1" role="tabpanel" aria-labelledby="tab1">
Content 1
</div>
<div id="panel2" role="tabpanel" aria-labelledby="tab2" hidden>
Content 2
</div>
<!--
5. aria-hidden on focusable elements
Problem: The element is hidden from screen readers but remains focusable, creating an inconsistent and confusing experience.
-->
<!-- Bad -->
<button aria-hidden="true">
Close
</button>
<!-- Better -->
<button type="button">
Close
</button>
<!-- Or, if it should truly be hidden -->
<button type="button" hidden>
Close
</button>
<!--
6. ARIA instead of native HTML semantics
Problem: Unnecessary complexity is introduced, and native features such as keyboard behavior, focus handling, and state communication are not provided automatically.
-->
<!-- Bad -->
<div role="checkbox" aria-checked="false" onclick="toggleCheckbox(this)">
Subscribe to newsletter
</div>
<!-- Better -->
<label>
<input type="checkbox" name="newsletter">
Subscribe to newsletter
</label>
<!--
7. aria-hidden removes content from the accessibility tree
Problem: Content becomes completely unavailable to assistive technologies, even though it remains visually present.
-->
<!-- Bad -->
<p aria-hidden="true">
Important information for all users
</p>
<!-- Better -->
<p>
Important information for all users
</p>Readability and Adaptability
WCAG defines a set of concrete requirements to ensure that content remains perceivable and usable under varying conditions. These include sufficient color contrast (1.4.3 Contrast (Minimum)[17]), text scalability (1.4.4 Resize Text)[18], responsive behavior without loss of information (1.4.10 Reflow)[19], the avoidance of conveying information solely through color (1.4.1 Use of Color)[20], and the ability to pause, stop, or hide moving content (2.2.2 Pause, Stop, Hide)[21].
These requirements ensure that content remains accessible across different usage contexts, for example, when text is enlarged, when viewed on smaller screens, or when users have visual impairments.
In practice, issues often arise from insufficient technical implementation. Common problems include low contrast between text and background, text placed over images without adequate readability, removed or barely visible focus indicators, fixed container heights that truncate content, and layouts that break or overlap when text is resized or zoomed. Equally problematic are cases where information is conveyed solely through color, as well as animations or auto-updating content that cannot be paused or stopped.
These issues are frequently perceived as purely visual or design-related concerns. However, they represent functional accessibility failures. If text cannot be resized effectively, or if content is lost during reflow, the interface becomes partially or entirely unusable for certain users. Accessibility therefore requires not only thoughtful visual design, but also a technically robust implementation that reliably supports diverse presentation contexts.
Common Mistakes: Code Exampleshtml
<!--
1. Insufficient color contrast
Problem: Text becomes difficult or impossible to read for many users, especially users with low vision.
-->
<!-- Bad -->
<style>
.text {
color: #aaa;
background: #fff;
}
</style>
<p class="text">Important information</p>
<!-- Better -->
<style>
.text {
color: #222;
background: #fff;
}
</style>
<p class="text">Important information</p>
<!--
2. Text over images without sufficient contrast
Problem: Background images can significantly reduce readability, especially when text is placed directly on visually complex areas.
-->
<!-- Bad -->
<div style="background: url('image.jpg'); color: white;">
Welcome to our website
</div>
<!-- Better -->
<div style="position: relative;">
<img src="image.jpg" alt="" style="width: 100%;">
<div style="
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.55);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
">
Welcome to our website
</div>
</div>
<!--
3. Fixed heights that truncate text
Problem: When users enlarge text, content may be cut off or become unreadable.
-->
<!-- Bad -->
<style>
.box {
height: 50px;
overflow: hidden;
}
</style>
<div class="box">
Long text that will be cut off when the font size is increased.
</div>
<!-- Better -->
<style>
.box {
min-height: 50px;
}
</style>
<div class="box">
Long text that can expand naturally when the font size is increased.
</div>
<!--
4. Layout breaks when text is enlarged
Problem: Content may overlap, disappear, or become difficult to use when users resize text or zoom the page.
-->
<!-- Bad -->
<style>
.container {
display: flex;
width: 300px;
}
.item {
width: 150px;
}
</style>
<div class="container">
<div class="item">Text 1</div>
<div class="item">Text 2</div>
</div>
<!-- Better -->
<style>
.container {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.item {
flex: 1 1 12rem;
}
</style>
<div class="container">
<div class="item">Text 1</div>
<div class="item">Text 2</div>
</div>
<!--
5. Information conveyed by color alone
Problem: Users who cannot perceive color differences, as well as screen reader users, may not understand the meaning.
-->
<!-- Bad -->
<p style="color: red;">Password is too short</p>
<!-- Better -->
<p>
<strong>Error:</strong> Password is too short.
</p>
<!--
6. Invisible focus indicator
Problem: Keyboard users cannot see where they are on the page.
-->
<!-- Bad -->
<style>
:focus {
outline: none;
}
</style>
<button>Continue</button>
<!-- Better -->
<style>
:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}
</style>
<button>Continue</button>
<!--
7. Animation without a pause or stop mechanism
Problem: Motion can distract users or cause discomfort; users need a way to pause or stop moving content.
-->
<!-- Bad -->
<div class="animation"></div>
<style>
.animation {
width: 100px;
height: 100px;
background: currentColor;
animation: move 1s infinite alternate;
}
@keyframes move {
from { transform: translateX(0); }
to { transform: translateX(200px); }
}
</style>
<!-- Better -->
<button type="button" onclick="toggleAnimation()">
Pause animation
</button>
<div class="animation"></div>
<style>
.animation {
width: 100px;
height: 100px;
background: currentColor;
animation: move 1s infinite alternate;
}
.animation.is-paused {
animation-play-state: paused;
}
@keyframes move {
from { transform: translateX(0); }
to { transform: translateX(200px); }
}
</style>
<script>
function toggleAnimation() {
const animation = document.querySelector('.animation');
animation.classList.toggle('is-paused');
}
</script>Forms, Validation, and Feedback
Forms are among the most complex aspects of accessible web applications, as they must satisfy multiple requirements simultaneously: clear labeling, understandable instructions, meaningful grouping, reliable input validation, proper focus management, and accessible feedback.
WCAG consolidates these requirements under the principle that users must be supported in avoiding and correcting errors. Specifically, success criteria 3.3.1 (Error Identification)[22], 3.3.2 (Labels or Instructions)[23], and 3.3.3 (Error Suggestion)[24] require that errors be clearly identified, described in an understandable manner, and, where possible, accompanied by actionable guidance for correction.
Problems arise when these requirements are not adequately implemented. Common issues include required fields indicated solely by color, format instructions provided only via placeholders, and error messages that are presented visually but not programmatically associated with their corresponding inputs. Additional challenges include vague or generic error messages, feedback that is not announced to assistive technologies (e.g., during dynamic validation), and forms that discard user input after an error occurs.
Another critical aspect is the communication of states and changes. Feedback, such as validation errors or confirmation messages, must be implemented in a way that makes it perceivable to assistive technologies, for example through properly associated descriptions or ARIA live regions.
Effective form design must support users both preventively and reactively. This means helping users avoid errors through clear instructions and sensible defaults, while also providing efficient mechanisms for error recovery. Accessible form implementation therefore goes beyond merely indicating that something is wrong; it actively supports users in understanding and resolving issues quickly and effectively.
Common Mistakes: Code Exampleshtml
<!--
1. Required fields indicated by color alone
Problem: Users may not understand the meaning of the visual indication if they cannot perceive color or use a screen reader.
-->
<!-- Bad -->
<label for="email">Email</label>
<input id="email" name="email" style="border-color: red;">
<!-- Better -->
<label for="email">
Email <span aria-hidden="true">*</span>
</label>
<input
id="email"
name="email"
type="email"
required
aria-describedby="email-hint"
autocomplete="email"
>
<p id="email-hint">Required field</p>
<!--
2. Format instructions provided only as placeholder text
Problem: Placeholder text disappears during input and is not a reliable, persistent instruction.
-->
<!-- Bad -->
<input type="text" placeholder="DD.MM.YYYY">
<!-- Better -->
<label for="birthdate">Date of birth</label>
<p id="birthdate-hint">Format: DD.MM.YYYY</p>
<input
id="birthdate"
name="birthdate"
type="text"
autocomplete="bday"
aria-describedby="birthdate-hint"
>
<!--
3. Errors presented only visually
Problem: Assistive technologies may not reliably identify or announce the error.
-->
<!-- Bad -->
<label for="password">Password</label>
<input id="password" name="password" type="password" style="border-color: red;">
<p style="color: red;">Too short</p>
<!-- Better -->
<label for="password">Password</label>
<input
id="password"
name="password"
type="password"
aria-invalid="true"
aria-describedby="password-error"
>
<p id="password-error">
Error: The password must be at least 8 characters long.
</p>
<!--
4. Vague error messages
Problem: Users are told that something is wrong, but not how to correct it.
-->
<!-- Bad -->
<label for="phone">Phone number</label>
<input id="phone" name="phone" type="tel" aria-invalid="true">
<p>Invalid input</p>
<!-- Better -->
<label for="phone">Phone number</label>
<input
id="phone"
name="phone"
type="tel"
aria-invalid="true"
aria-describedby="phone-error phone-hint"
autocomplete="tel"
>
<p id="phone-hint">Example: +49 30 1234567</p>
<p id="phone-error">
Error: Please enter the phone number including the country code.
</p>
<!--
5. Feedback that is not announced
Problem: Screen reader users may not notice changes such as success messages or validation errors.
-->
<!-- Bad -->
<form onsubmit="showMessage(); return false;">
<label for="newsletter-email">Email</label>
<input id="newsletter-email" name="email" type="email">
<button>Subscribe</button>
</form>
<div id="message"></div>
<!-- Better -->
<form onsubmit="showMessage(); return false;">
<label for="newsletter-email-good">Email</label>
<input id="newsletter-email-good" name="email" type="email" autocomplete="email">
<button>Subscribe</button>
</form>
<div id="message-good" role="status" aria-live="polite"></div>
<script>
function showMessage() {
document.getElementById('message-good').textContent =
'Thank you, your subscription has been saved.';
}
</script>
<!--
6. User input is lost after an error
Problem: Users must re-enter their information, making correction harder and increasing the risk of abandonment.
-->
<!-- Bad -->
<form>
<label for="name">Name</label>
<input id="name" name="name" value="">
<label for="email-lost">Email</label>
<input id="email-lost" name="email" value="">
<p>Error: Please check your input.</p>
</form>
<!-- Better -->
<form>
<label for="name-good">Name</label>
<input id="name-good" name="name" value="Max Mustermann" autocomplete="name">
<label for="email-preserved">Email</label>
<input
id="email-preserved"
name="email"
type="email"
value="max@example"
aria-invalid="true"
aria-describedby="email-error"
autocomplete="email"
>
<p id="email-error">
Error: Please enter a complete email address, for example max@example.com.
</p>
</form>
<!--
7. Error summary without focus management
Problem: After submission, users are not taken to the error summary and may not know where errors occurred or how to reach them.
-->
<!-- Bad -->
<form>
<p>There are errors in the form.</p>
<label for="street">Street</label>
<input id="street" name="street">
<label for="zip">Postal code</label>
<input id="zip" name="zip">
</form>
<!-- Better -->
<form>
<div role="alert" tabindex="-1" id="error-summary">
<h2>Please correct the following errors:</h2>
<ul>
<li><a href="#street-good">Street is required.</a></li>
<li><a href="#zip-good">Postal code must contain 5 digits.</a></li>
</ul>
</div>
<label for="street-good">Street</label>
<input
id="street-good"
name="street"
aria-invalid="true"
aria-describedby="street-error"
autocomplete="street-address"
>
<p id="street-error">Error: Please enter your street.</p>
<label for="zip-good">Postal code</label>
<input
id="zip-good"
name="zip"
inputmode="numeric"
aria-invalid="true"
aria-describedby="zip-error"
autocomplete="postal-code"
>
<p id="zip-error">Error: The postal code must contain 5 digits.</p>
</form>
<script>
document.getElementById('error-summary').focus();
</script>Why These Errors Recur
Accessibility issues rarely arise from isolated mistakes; rather, they are often rooted in systemic patterns within design and development processes. Design systems frequently prioritize visual consistency and styling, while behavior, interaction, and semantic correctness are treated as secondary concerns. As a result, components are often developed as branding artifacts rather than as robust, accessible building blocks.
This is compounded by an overreliance on automated testing. While such tools are effective at identifying certain classes of technical issues, they capture only a limited subset of actual accessibility barriers. When accessibility is assessed primarily through automation, critical aspects, such as interaction logic, focus management, and overall usability, often remain undetected. At the same time, accessibility is frequently introduced late in the development lifecycle, rather than being treated as an integral part of architecture and component design from the outset.
Another key factor is the level of abstraction in modern frontend architectures. Errors are rarely confined to individual instances; instead, they become embedded in reusable components or design patterns and are then propagated systematically. A flawed button implementation, an inaccessible form control, or an inconsistent interaction pattern can thus spread across an entire product or even multiple applications.
For this reason, the component layer represents the most effective leverage point for sustainable accessibility. When foundational UI elements are correctly implemented, thoroughly tested, and well-documented, many accessibility issues can be prevented at their source before they propagate throughout the system.
How Teams Can Test Earlier
An effective approach to ensuring accessibility is inherently multi-layered and must be integrated early in the development process. First, teams should consistently rely on semantic defaults and prioritize native HTML elements. These provide built-in accessibility features, such as semantics, interaction patterns, and focus behavior, thereby significantly reducing implementation complexity and the risk of errors.
Automated testing can support this process, but it must be applied with a clear understanding of its limitations. Such tools are well-suited to detecting common and easily identifiable issues, such as missing alternative text or insufficient color contrast, but they capture only a subset of real-world accessibility barriers.
Complementing automation, targeted manual testing is essential. This includes evaluating full keyboard operability, verifying visible focus states, ensuring proper focus management in components such as dialogs, and testing behavior under zoom and reflow conditions (e.g., up to 400%). Additional checks should include increased text spacing, deliberate invalid form inputs to assess validation and feedback mechanisms, and the behavior of dynamic or asynchronous content to ensure that updates are perceivable by assistive technologies.
Taken together, these practices enable teams to identify accessibility issues early and systematically, before they become embedded in components or propagate throughout the system.
Conclusion
Accessibility improves when recurring implementation patterns are identified early and systematically addressed at both the component and markup levels. The key is not the retrospective correction of isolated issues, but the establishment of robust technical foundations that are consistently applied across an entire system.
The central principle for developing and evaluating components is: whenever native browser behavior is replaced, the full responsibility for its accessibility must be assumed including semantics, interaction, state management, and focus behavior.
Sources
- [1]WebAIM Million 2025 Report
- [2]Evaluating Web Accessibility Overview
- [3]Accessibility Principles
- [4]WCAG 2.1 – Einführung (POUR-Prinzipien)
- [5]W3C WAI – Page Structure Tutorial
- [6]MDN – Structuring content with HTML
- [7]WCAG 2.1 – 1.3.1 Info and Relationships
- [8]WCAG 2.1 – 1.1.1 Non-text Content
- [9]WCAG 2.1 – 4.1.2 Name, Role, Value
- [10]WCAG 2.1 – 3.3.2 Labels or Instructions
- [11]MDN – Accessible Name
- [12]WCAG 2.1 – 2.1.1 Keyboard
- [13]WCAG 2.1 – 2.1.2 No Keyboard Trap
- [14]WCAG 2.1 – 2.4.7 Focus Visible
- [15]WAI-ARIA – Introduction
- [16]MDN – aria-hidden
- [17]WCAG 2.1 – 1.4.3 Contrast (Minimum)
- [18]WCAG 2.1 – 1.4.4 Resize Text
- [19]WCAG 2.1 – 1.4.10 Reflow
- [20]WCAG 2.1 – 1.4.1 Use of Color
- [21]WCAG 2.1 – 2.2.2 Pause, Stop, Hide
- [22]WCAG 2.1 – 3.3.1 Error Identification
- [23]WCAG 2.1 – 3.3.2 Labels or Instructions
- [24]WCAG 2.1 – 3.3.3 Error Suggestion
- [25]W3C WAI – Forms Tutorial
![[object Object]](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fqnbxd1h1%2Fproduction%2F6374b7750591acb041c9b72506e78aef314d7698-2007x2257.png&w=3840&q=75)
Flo Winkler
Software Engineer


Why Building Everything Faster is Actually Making Your Product Worse
Convinced that we are the right ones for your project? Let's work together!
Begin your inquiry now
Contact us via email, and we will get back to you promptly.