Teil unserer Compliance & Regulation-Serie
Den vollständigen Leitfaden lesenBarrierefreiheit im Internet: WCAG 2.1 AA Compliance Guide
Barrierefreiheit ist keine Funktion, die Sie nach dem Start hinzufügen – sie ist ein grundlegendes Qualitätsmerkmal, genau wie Leistung oder Sicherheit. Die Einhaltung von WCAG 2.1 AA ist mittlerweile in der EU (European Accessibility Act, in Kraft getreten im Juni 2025), den USA (Rechtsprechung zu ADA Title III) und vielen anderen Gerichtsbarkeiten gesetzlich vorgeschrieben. Über die Compliance hinaus erzielen barrierefreie Schnittstellen bessere Konvertierungen, ein höheres Ranking in der Suche und dienen schätzungsweise 1,3 Milliarden Menschen mit Behinderungen weltweit.
Bei diesem Leitfaden handelt es sich um ein praktisches Umsetzungshandbuch, nicht um eine Checkliste. Sie lernen die vier WCAG-Prinzipien, die wirkungsvollsten Techniken, das systematische Testen und die Integration der Barrierefreiheit in Ihren React/Next.js-Entwicklungsworkflow kennen, damit diese stabil bleibt.
Wichtige Erkenntnisse
- WCAG 2.1 AA erfordert alle vier POUR-Prinzipien: wahrnehmbar, bedienbar, verständlich, robust
- Beginnen Sie mit semantischem HTML – es bietet 70 % der Barrierefreiheit kostenlos, bevor ARIA hinzugefügt wird
- Mindestfarbkontrastverhältnis: 4,5:1 für normalen Text, 3:1 für großen Text (18pt/14pt fett)
- Jedes interaktive Element muss über die Tastatur fokussierbar sein und über eine sichtbare Fokusanzeige verfügen – Sprachausgaben von Bildschirmleseprogrammen basieren auf dem Barrierefreiheitsbaum – testen Sie mit NVDA (Windows) und VoiceOver (Mac)
- ARIA ist der letzte Ausweg – es ändert nur die Art und Weise, wie unterstützende Technologien das DOM interpretieren, nicht das Verhalten
- Automatisieren Sie mit Axe-Core in Ihrer CI-Pipeline; Manuelle Tests erfassen, was der Automatisierung entgeht
- Dokumentieren Sie Ihre Erklärung zur Barrierefreiheit und stellen Sie Benutzern einen Feedback-Mechanismus zur Verfügung, um Probleme zu melden
Die vier POUR-Prinzipien
WCAG 2.1 basiert auf vier Prinzipien. Jedes Erfolgskriterium gehört zu einem davon.
Wahrnehmbar: Informationen müssen so darstellbar sein, dass Benutzer sie wahrnehmen können. Dazu gehören Textalternativen für Bilder, Bildunterschriften für Videos, ausreichender Farbkontrast und Inhalte, die sich nicht allein auf die Farbe verlassen, um Bedeutung zu vermitteln.
Bedienbar: Alle Funktionen müssen über die Tastatur bedienbar sein, mit genügend Zeit zur Interaktion, ohne anfallsauslösende Inhalte und einer navigierbaren Struktur (Links überspringen, Seitentitel, Fokusreihenfolge).
Verständlich: Inhalte müssen lesbar und vorhersehbar sein. Die Sprache muss identifiziert werden, Fehlermeldungen müssen beschreibend sein und Formulare müssen klare Beschriftungen und Validierungsrückmeldungen enthalten.
Robust: Inhalte müssen durch aktuelle und zukünftige unterstützende Technologien interpretierbar sein. Dies bedeutet gültiges HTML, ordnungsgemäße ARIA-Verwendung und Statusmeldungen, die ohne Fokussierung angekündigt werden.
Semantisches HTML zuerst
Semantisches HTML ist die Investition mit dem größten Nutzen in die Barrierefreiheit. Native HTML-Elemente verfügen über integrierte Barrierefreiheitsrollen, Zustände und Tastaturverhalten – kein ARIA erforderlich.
// BAD: Generic divs with no semantics
<div class="button" onclick="submit()">Submit</div>
<div class="nav">
<div class="link" onclick="navigate('/home')">Home</div>
</div>
// GOOD: Native semantics, free keyboard and screen reader support
<button type="submit" onClick={submit}>Submit</button>
<nav aria-label="Main navigation">
<a href="/home">Home</a>
</nav>
Orientierungsbereiche erleichtern Benutzern von Bildschirmleseprogrammen die schnelle Navigation, indem sie zwischen Abschnitten springen:
// Every page should have these landmarks
<header> {/* banner landmark */}
<nav aria-label="Main">...</nav>
</header>
<main> {/* main landmark */}
<h1>Page Title</h1>
<article>...</article>
<aside aria-label="Related content">...</aside>
</main>
<footer> {/* contentinfo landmark */}
<nav aria-label="Footer">...</nav>
</footer>
Die Überschriftenhierarchie muss logisch und ununterbrochen sein:
// BAD: Skipped heading levels
<h1>Page Title</h1>
<h3>Section</h3> {/* Skipped h2! */}
// GOOD: Sequential hierarchy
<h1>Page Title</h1>
<h2>Section</h2>
<h3>Subsection</h3>
Farbkontrast
WCAG 2.1 AA erfordert:
- 4,5:1 Kontrastverhältnis für normalen Text (unter 18pt / 14pt fett)
- Kontrastverhältnis 3:1 für großen Text (18pt+ / 14pt+ fett)
- 3:1 für UI-Komponenten und grafische Objekte (Schaltflächen, Symbole, Eingaberahmen)
// Tailwind color contrast examples
// FAIL: gray-400 on white (#9ca3af on #fff = 2.8:1)
<p className="text-gray-400">This fails AA</p>
// PASS: gray-700 on white (#374151 on #fff = 10.7:1)
<p className="text-gray-700">This passes AA</p>
// For dark mode, test both themes separately
<p className="text-gray-700 dark:text-gray-300">
gray-700 on white (10.7:1) / gray-300 on gray-900 (9.2:1)
</p>
Verwenden Sie während der Entwicklung den WebAIM Contrast Checker oder das Browser-Kontrasttool DevTools. Fügen Sie dies Ihrem Storybook oder Design-Token-System hinzu, um Regressionen abzufangen:
// contrast-checker.ts
import { getContrast } from 'polished';
function assertContrast(fg: string, bg: string, level: 'AA' | 'AAA' = 'AA') {
const ratio = getContrast(fg, bg);
const required = level === 'AA' ? 4.5 : 7;
if (ratio < required) {
throw new Error(
`Contrast ratio ${ratio.toFixed(2)}:1 fails WCAG ${level} (requires ${required}:1)`
);
}
}
Tastaturnavigation
Jedes interaktive Element – Links, Schaltflächen, Formularfelder, benutzerdefinierte Widgets – muss über die Tastatur erreichbar und bedienbar sein.
Fokusmanagement
// Skip link: first element on every page
// Allows keyboard users to jump past navigation
export function SkipLink() {
return (
<a
href="#main-content"
className="sr-only focus:not-sr-only focus:fixed focus:top-4 focus:left-4
focus:z-50 focus:px-4 focus:py-2 focus:bg-blue-600 focus:text-white
focus:rounded focus:ring-2 focus:ring-white"
>
Skip to main content
</a>
);
}
// Main content target
<main id="main-content" tabIndex={-1}>
{/* tabIndex={-1} allows programmatic focus without appearing in tab order */}
Focus Trapping in Modalen
Wenn ein Dialog geöffnet wird, muss der Fokus darin gefangen sein. Beim Schließen kehrt der Fokus zum Auslöser zurück:
// focus-trap.tsx using @radix-ui/react-focus-trap (used internally by shadcn Dialog)
import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog';
import { useRef } from 'react';
export function AccessibleModal({ trigger, children, title }: Props) {
const triggerRef = useRef<HTMLButtonElement>(null);
return (
<Dialog>
<DialogTrigger ref={triggerRef} asChild>
<button>Open</button>
</DialogTrigger>
<DialogContent
// shadcn Dialog handles focus trap and returns focus to trigger on close
aria-describedby="dialog-description"
>
<DialogTitle>{title}</DialogTitle>
<p id="dialog-description" className="sr-only">
{/* Screen reader description of dialog purpose */}
</p>
{children}
</DialogContent>
</Dialog>
);
}
Sichtbare Fokusindikatoren
WCAG 2.1 SC 2.4.11 (AA in WCAG 2.2) erfordert einen Fokusumriss von mindestens 2 Pixeln. Den Fokus niemals ersatzlos unterdrücken:
/* globals.css */
/* NEVER do this: */
:focus { outline: none; }
/* DO this: custom, visible focus ring */
:focus-visible {
outline: 2px solid hsl(var(--ring));
outline-offset: 2px;
border-radius: 4px;
}
/* Remove for mouse users (only show for keyboard) */
:focus:not(:focus-visible) {
outline: none;
}
ARIA: Wann und wie man es verwendet
ARIA-Attribute (Accessible Rich Internet Applications) verändern die Art und Weise, wie unterstützende Technologien das DOM interpretieren. Die erste Regel von ARIA: Verwenden Sie es nicht, wenn für Ihren Anwendungsfall ein natives HTML-Element vorhanden ist.
ARIA-Etiketten
// Icon-only button — screen reader has nothing to announce without aria-label
<button aria-label="Close dialog">
<X className="h-4 w-4" aria-hidden="true" />
</button>
// Form field with visible label — use htmlFor, not aria-label
<label htmlFor="email">Email address</label>
<input id="email" type="email" />
// Input with visible description
<input
id="password"
type="password"
aria-describedby="password-requirements"
/>
<p id="password-requirements">Must be at least 12 characters.</p>
ARIA Live-Regionen
Kündigen Sie dynamische Inhaltsänderungen an, ohne den Fokus zu verschieben:
// Status messages (search results count, form submission status)
function SearchResults({ count, loading }: Props) {
return (
<>
{/* aria-live="polite" waits for user to finish current action */}
<div aria-live="polite" aria-atomic="true" className="sr-only">
{loading ? 'Loading results...' : `${count} results found`}
</div>
{/* Visual result count (not for screen readers — aria-hidden) */}
<span aria-hidden="true">{count} results</span>
</>
);
}
// Error messages (aria-live="assertive" interrupts immediately)
function FormError({ error }: { error: string | null }) {
return (
<div
role="alert"
aria-live="assertive"
className={cn('text-red-500 text-sm', !error && 'hidden')}
>
{error}
</div>
);
}
ARIA für benutzerdefinierte Widgets
Wenn Sie ein benutzerdefiniertes Widget (Registerkarte, Baumansicht, Kombinationsfeld) erstellen müssen, befolgen Sie genau die Muster des ARIA Authoring Practices Guide (APG):
// Accessible tabs (ARIA tab pattern)
export function Tabs({ items }: { items: Tab[] }) {
const [active, setActive] = useState(0);
return (
<div>
<div role="tablist" aria-label="Content tabs">
{items.map((item, i) => (
<button
key={item.id}
role="tab"
aria-selected={active === i}
aria-controls={`panel-${item.id}`}
id={`tab-${item.id}`}
tabIndex={active === i ? 0 : -1} // Roving tabindex
onClick={() => setActive(i)}
onKeyDown={(e) => {
if (e.key === 'ArrowRight') setActive((active + 1) % items.length);
if (e.key === 'ArrowLeft') setActive((active - 1 + items.length) % items.length);
}}
>
{item.label}
</button>
))}
</div>
{items.map((item, i) => (
<div
key={item.id}
role="tabpanel"
id={`panel-${item.id}`}
aria-labelledby={`tab-${item.id}`}
hidden={active !== i}
>
{item.content}
</div>
))}
</div>
);
}
Formulare und Fehlerbehandlung
Barrierefreie Formulare gehören zu den wirkungsvollsten Verbesserungen für Benutzer mit kognitiven und motorischen Behinderungen.
// Accessible form field with error state
function TextField({
id,
label,
error,
required,
hint,
...props
}: TextFieldProps) {
const hintId = hint ? `${id}-hint` : undefined;
const errorId = error ? `${id}-error` : undefined;
const describedBy = [hintId, errorId].filter(Boolean).join(' ') || undefined;
return (
<div>
<label htmlFor={id} className="font-medium">
{label}
{required && <span aria-hidden="true" className="text-red-500 ml-1">*</span>}
{required && <span className="sr-only">(required)</span>}
</label>
{hint && (
<p id={hintId} className="text-sm text-gray-500 mt-1">
{hint}
</p>
)}
<input
id={id}
aria-required={required}
aria-invalid={!!error}
aria-describedby={describedBy}
className={cn('input', error && 'border-red-500')}
{...props}
/>
{error && (
<p id={errorId} className="text-sm text-red-500 mt-1" role="alert">
{error}
</p>
)}
</div>
);
}
Bilder und Medien
// Informative image
<img src="/chart.png" alt="Bar chart showing 40% revenue growth in Q4 2025" />
// Decorative image — empty alt hides it from screen readers
<img src="/divider.png" alt="" role="presentation" />
// Complex image — use aria-describedby for long descriptions
<figure>
<img
src="/architecture.png"
alt="System architecture diagram"
aria-describedby="arch-desc"
/>
<figcaption id="arch-desc">
The diagram shows three tiers: frontend Next.js on port 3000,
NestJS API on port 3001, and PostgreSQL database on port 5433.
Redis sits between the API and database layers.
</figcaption>
</figure>
// SVG icons used as decoration
<svg aria-hidden="true" focusable="false">
<use href="#icon-search" />
</svg>
Automatisiertes Testen mit Axe-Core
pnpm add -D @axe-core/playwright axe-core
// tests/a11y/homepage.spec.ts
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';
test.describe('Homepage accessibility', () => {
test('should have no WCAG 2.1 AA violations', async ({ page }) => {
await page.goto('/');
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])
.exclude('#third-party-widget') // Exclude known external violations
.analyze();
expect(results.violations).toEqual([]);
});
test('should be keyboard navigable', async ({ page }) => {
await page.goto('/');
// Tab through interactive elements and verify focus is visible
await page.keyboard.press('Tab');
const focusedElement = await page.evaluate(
() => document.activeElement?.getAttribute('href')
);
expect(focusedElement).toBe('#main-content'); // Skip link
});
});
Zur CI-Pipeline hinzufügen:
# .github/workflows/ci.yml
- name: Run accessibility tests
run: cd apps/web && npx playwright test tests/a11y --reporter=html
- uses: actions/upload-artifact@v4
with:
name: a11y-report
path: apps/web/playwright-report/
Häufig gestellte Fragen
Was ist der Unterschied zwischen WCAG 2.1 A, AA und AAA?
Level A ist das Minimum – ein Nichtbestehen von Level A bedeutet, dass der Inhalt für einige Benutzer grundsätzlich nicht zugänglich ist. Stufe AA ist in den meisten Gerichtsbarkeiten der Rechtsstandard und zielt auf die breitesten Benutzerbedürfnisse ab. Die Stufe AAA ist ehrgeizig – einige Kriterien können nicht für alle Inhaltstypen erfüllt werden. Streben Sie die AA-Konformität als Grundlage an und streben Sie, wo möglich, die AAA-Konformität an.
Macht die Verwendung einer Komponentenbibliothek wie shadcn/ui meine App zugänglich?
shadcn/ui basiert auf Radix-UI-Primitiven, die per Design zugänglich sind – sie umfassen korrekte ARIA-Rollen, Tastaturnavigation und Fokusverwaltung. Sie müssen jedoch weiterhin aussagekräftige Beschriftungen hinzufügen, Fehlerzustände verständlich behandeln, einen ausreichenden Farbkontrast zu Ihrem benutzerdefinierten Design sicherstellen und mit echten Hilfstechnologien testen. Komponentenbibliotheken reduzieren den Aufwand, machen aber Barrierefreiheitstests nicht überflüssig.
Wie teste ich mit einem Screenreader?
Verwenden Sie unter Windows NVDA (kostenlos) mit Firefox oder Chrome. Verwenden Sie unter macOS VoiceOver (integriert, Cmd+F5) mit Safari. Verwenden Sie auf Mobilgeräten TalkBack (Android) oder VoiceOver (iOS). Testen Sie wichtige Benutzerreisen: Ausfüllen von Formularen, modale Interaktionen, Navigation über Orientierungspunkte und Lesen dynamischer Inhalte. Screenreader-Tests erfassen Ankündigungen, Lesereihenfolge und Fokusverhalten, die automatisierten Tools entgehen.
Was ist das Roving-Tabindex-Muster?
Roving Tabindex ist das Tastaturmuster für zusammengesetzte Widgets (Registerkartenlisten, Symbolleisten, Optionsgruppen, Baumansichten). Nur ein Element in der Gruppe hat jeweils tabIndex={0} – das aktive Element. Alle anderen erhalten tabIndex={-1}. Mit den Pfeiltasten wird der Fokus innerhalb der Gruppe verschoben und aktualisiert, welches Element den tabIndex 0 hat. Dadurch wird verhindert, dass der Benutzer mit der Tabulatortaste durch jedes Element in der Gruppe scrollt – er betritt die Gruppe mit der Tabulatortaste, navigiert mit den Pfeiltasten und verlässt die Gruppe mit der Tabulatortaste.
Wie gehe ich mit der Barrierefreiheit für dynamische Inhalte um, die über AJAX geladen werden?
Verwenden Sie aria-live-Regionen für Statusaktualisierungen (Zählung der Suchergebnisse, Speicherbestätigungen). Verschieben Sie beim Ersetzen ganzer Seitenabschnitte den Fokus nach dem Laden auf die Überschrift oder den Container des neuen Inhalts. Verwenden Sie für Ladezustände aria-busy="true" für die Region, die aktualisiert wird, und eine aria-live="polite"-Region, um den Abschluss anzukündigen. Testen Sie immer mit einem Screenreader, um sicherzustellen, dass Ankündigungen klar und rechtzeitig sind.
Nächste Schritte
Die Barrierefreiheit im Internet ist eine fortlaufende Praxis und keine einmalige Prüfung. Beginnen Sie mit der Korrektur Ihres semantischen HTML- und Farbkontrasts, fügen Sie dann Tastaturnavigation und ARIA für komplexe Widgets hinzu und automatisieren Sie die WCAG-Validierung in Ihrer CI-Pipeline, um Regressionen zu erkennen.
ECOSIRE erstellt WCAG 2.1 AA-konforme Webanwendungen als Basisstandard für jedes Projekt. Wenn Sie eine Prüfung der Barrierefreiheit benötigen oder von Grund auf konform bauen möchten, entdecken Sie unsere Frontend-Engineering-Dienste.
Geschrieben von
ECOSIRE Research and Development Team
Entwicklung von Enterprise-Digitalprodukten bei ECOSIRE. Einblicke in Odoo-Integrationen, E-Commerce-Automatisierung und KI-gestützte Geschäftslösungen.
Verwandte Artikel
Audit Preparation Checklist: Getting Your Books Ready
Complete audit preparation checklist covering financial statement readiness, supporting documentation, internal controls documentation, auditor PBC lists, and common audit findings.
Australian GST Guide for eCommerce Businesses
Complete Australian GST guide for eCommerce businesses covering ATO registration, the $75,000 threshold, low value imports, BAS lodgement, and GST for digital services.
Canadian HST/GST Guide: Province-by-Province
Complete Canadian HST/GST guide covering registration requirements, province-by-province rates, input tax credits, QST, place of supply rules, and CRA compliance.
Mehr aus Compliance & Regulation
Audit Preparation Checklist: Getting Your Books Ready
Complete audit preparation checklist covering financial statement readiness, supporting documentation, internal controls documentation, auditor PBC lists, and common audit findings.
Australian GST Guide for eCommerce Businesses
Complete Australian GST guide for eCommerce businesses covering ATO registration, the $75,000 threshold, low value imports, BAS lodgement, and GST for digital services.
Canadian HST/GST Guide: Province-by-Province
Complete Canadian HST/GST guide covering registration requirements, province-by-province rates, input tax credits, QST, place of supply rules, and CRA compliance.
Healthcare Accounting: Compliance and Financial Management
Complete guide to healthcare accounting covering HIPAA financial compliance, contractual adjustments, charity care, cost report preparation, and revenue cycle management.
India GST Compliance for Digital Businesses
Complete India GST compliance guide for digital businesses covering registration, GSTIN, rates, input tax credits, e-invoicing, GSTR returns, and TDS/TCS provisions.
Fund Accounting for Nonprofits: Best Practices
Master nonprofit fund accounting with net asset classifications, grant tracking, Form 990 preparation, functional expense allocation, and audit readiness best practices.