Zum Hauptinhalt springen

Web-Zugänglichkeit (a11y) in Cursor: WCAG, ARIA und axe-core

Web-Zugänglichkeit in Cursor

Web-Zugänglichkeit (a11y) stellt sicher, dass jeder, einschließlich Menschen mit Behinderungen, Ihre Anwendung wahrnehmen, verstehen und mit ihr interagieren kann. Cursor, ein KI-gestützter IDE-Editor, beschleunigt die zugängliche Entwicklung durch das Generieren ARIA-konformer Auszeichnung, das Ausführen automatisierter Audits und das Anwenden von WCAG-Korrekturen in Ihrer gesamten Codebasis. Dieser Leitfaden behandelt ARIA-Labels, WCAG-Konformität, axe-core-Tests, KI-gestützte a11y-Korrekturen und Screenreader-Tests.

Voraussetzungen​

Bevor Sie beginnen, stellen Sie sicher, dass Sie Folgendes haben:

  • Cursor (neueste Version empfohlen) als IDE-Editor
  • Ein Web-Projekt (React, Vue oder einfaches HTML und JavaScript)
  • Node.js 18 oder höher für die Test-Tools
  • Grundlegende Vertrautheit mit HTML-Semantik
tipp

Zugänglichkeit ist deutlich günstiger, sie von Anfang an einzubauen, als sie nachzurüsten. Öffnen Sie Ihr Projekt von Anfang an in Cursor und lassen Sie die KI Komponenten auditeren, während Sie sie schreiben. Das Korrigieren eines fehlenden Labels während der Entwicklung dauert Sekunden; das Korrigieren desselben Problems in einer Produktions-App dauert Wochen.

WCAG-Konformität verstehen​

Die Web Content Accessibility Guidelines (WCAG) definieren, wie man Web-Inhalte zugänglich macht. Sie sind um vier Prinzipien herum organisiert, oft POUR genannt:

  • Wahrnehmbar: Informationen und Benutzeroberflächenkomponenten müssen für Benutzer wahrnehmbar präsentiert werden.
  • Bedienbar: Benutzeroberflächenkomponenten und Navigation müssen bedienbar sein.
  • Verständlich: Inhalt und Bedienung der Benutzeroberfläche müssen verständlich sein.
  • Robust: Inhalt muss robust genug sein, um von Hilfstechnologien interpretiert zu werden.

WCAG definiert drei Konformitätsstufen: A (Minimum), AA (das rechtliche Ziel für die meisten Organisationen) und AAA (erweitert). Bitten Sie Cursor, die Stufe-AA-Anforderungen für eine bestimmte Funktion zusammenzufassen:

Liste die WCAG 2.2 Stufe-AA-Erfolgskriterien auf, die auf ein
mehrstufiges Checkout-Formular mit Datumsauswahlen und
Kreditkarteneingaben zutreffen.

Cursor gibt die relevanten Kriterien zurück und erklärt, wie jedes mit konkreten Code-Vorschlägen erfüllt wird.

Grundlagen des semantischen HTML​

Semantisches HTML ist die Grundlage der Zugänglichkeit. Das richtige Element entfernt oft die Notwendigkeit für ARIA vollständig. Cursor hilft Ihnen, die richtige Auszeichnung zu wählen und zu generieren.

Semantische Komponenten generieren​

Bitten Sie Cursor, eine Navigationsleiste mit integrierter Zugänglichkeit zu erstellen:

Erstelle eine responsive Website-Navigation in React, die:
- Ein <nav>-Landmark mit einem zugänglichen Namen verwendet
- Einen Skip-Link am Anfang der Seite hat
- Ein mobiles Menü mit aria-expanded und aria-controls umschaltet
- Bei Escape schließt und den Fokus auf die Umschalttaste zurückgibt
- Vollständige Tastaturnavigation unterstützt

Cursor generiert die Komponente:

import { useState, useRef, useEffect } from 'react';

export function SiteNav({ links }: { links: { href: string; label: string }[] }) {
const [open, setOpen] = useState(false);
const toggleRef = useRef<HTMLButtonElement>(null);

useEffect(() => {
if (!open) return;
const onKey = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
setOpen(false);
toggleRef.current?.focus();
}
};
document.addEventListener('keydown', onKey);
return () => document.removeEventListener('keydown', onKey);
}, [open]);

return (
<>
<a href="#main" className="skip-link">Zum Hauptinhalt springen</a>
<nav aria-label="Hauptnavigation">
<button
ref={toggleRef}
aria-expanded={open}
aria-controls="mobile-menu"
onClick={() => setOpen((v) => !v)}
>
Menü
</button>
<ul id="mobile-menu" hidden={!open}>
{links.map((link) => (
<li key={link.href}>
<a href={link.href}>{link.label}</a>
</li>
))}
</ul>
</nav>
</>
);
}
tipp

Die erste Regel von ARIA lautet: Verwenden Sie kein ARIA, wenn ein natives HTML-Element existiert. Ein echtes <button> bietet Ihnen Tastaturfokus, Enter- und Space-Aktivierung und Screenreader-Semantik kostenlos. Bitten Sie Cursor: "Ersetze diesen div-basierten Button durch einen semantischen Button", wann immer Sie onClick auf einem nicht-interaktiven Element sehen.

ARIA-Labels und Rollen​

Wenn natives HTML die Semantik, die Sie benötigen, nicht ausdrücken kann, füllt ARIA die Lücke. Cursor generiert korrekte ARIA-Attribute und warnt vor häufigen Fehlern.

Zugängliche Formulare​

Formulareingaben benötigen Labels. Bitten Sie Cursor, ein zugängliches Formularfeld zu generieren:

Erstelle eine wiederverwendbare FormField-Komponente mit:
- Einem zugehörigen <label> unter Verwendung von htmlFor
- Einem aria-required-Attribut, wenn erforderlich
- Einem aria-describedby-Link zu Hilfs- und Fehlertext
- Fehlermeldungen mit role="alert"
import { useId } from 'react';

interface FormFieldProps {
label: string;
name: string;
type?: string;
required?: boolean;
error?: string;
helper?: string;
}

export function FormField({ label, name, type = 'text', required, error, helper }: FormFieldProps) {
const fieldId = useId();
const helperId = `${fieldId}-helper`;
const errorId = `${fieldId}-error`;
const describedBy = [helper && helperId, error && errorId].filter(Boolean).join(' ') || undefined;

return (
<div>
<label htmlFor={fieldId}>
{label}
{required && <span aria-hidden="true">*</span>}
</label>
<input
id={fieldId}
name={name}
type={type}
required={required}
aria-required={required}
aria-describedby={describedBy}
aria-invalid={!!error}
/>
{helper && !error && (
<p id={helperId} className="helper-text">{helper}</p>
)}
{error && (
<p id={errorId} role="alert" className="error-text">{error}</p>
)}
</div>
);
}

Live-Regionen für dynamische Updates​

Wenn sich Inhalte dynamisch aktualisieren (Benachrichtigungen, Suchergebnisse), benötigen Screenreader eine Live-Region, um Änderungen anzukündigen. Cursor generiert das Muster:

export function SearchResults({ query, results }: { query: string; results: string[] }) {
return (
<div
aria-live="polite"
aria-atomic="true"
role="status"
>
{results.length === 0 ? (
<p>Keine Ergebnisse für "{query}".</p>
) : (
<p>{results.length} Ergebnisse gefunden für "{query}".</p>
)}
<ul>
{results.map((r) => <li key={r}>{r}</li>)}
</ul>
</div>
);
}
warnung

Verwenden Sie aria-live="polite" für nicht dringende Updates und aria-live="assertive" nur für kritische Warnungen. Der übermäßige Gebrauch von assertiven Live-Regionen unterbricht Screenreader-Benutzer ständig und macht Ihre App unbenutzbar. Verwenden Sie niemals role="alert" für Erfolgsmeldungen; reservieren Sie es für tatsächliche Fehler, die sofortige Aufmerksamkeit erfordern.

Automatisierte Tests mit axe-core​

Automatisierte Tools erkennen etwa 30 bis 40 Prozent der Zugänglichkeitsprobleme. axe-core ist der Industriestandard. Cursor kann es in Ihre Test-Suite und CI-Pipeline integrieren.

axe-core mit Jest einrichten​

Bitten Sie Cursor, automatisierte Zugänglichkeitstests hinzuzufügen:

Füge axe-core zu meinem React-Projekt hinzu. Erstelle einen Jest-Test,
der die SiteNav-Komponente mit Testing Library rendert und axe-Regeln
ausführt.

Cursor installiert die Abhängigkeiten und schreibt den Test:

npm install -D @axe-core/react axe-core jest-axe @testing-library/react @testing-library/jest-dom
// src/components/SiteNav.test.tsx
import { render } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';
import { SiteNav } from './SiteNav';

expect.extend(toHaveNoViolations);

const links = [
{ href: '/', label: 'Startseite' },
{ href: '/about', label: 'Über uns' },
];

describe('SiteNav', () => {
it('hat keine Zugänglichkeitsverletzungen wenn geschlossen', async () => {
const { container } = render(<SiteNav links={links} />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});

it('hat keine Zugänglichkeitsverletzungen wenn geöffnet', async () => {
const { container, getByText } = render(<SiteNav links={links} />);
getByText('Menü').click();
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});

Wiederverwendbarer axe-Test-Helfer​

Cursor kann einen wiederverwendbaren Helfer generieren, damit jeder Komponententest konsistent bleibt:

import { render } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';

expect.extend(toHaveNoViolations);

export async function expectAccessible(component: React.ReactElement) {
const { container } = render(component);
const results = await axe(container, {
rules: {
// Deaktivieren Sie Regeln, die Sie woanders absichtlich behandeln
region: { enabled: false },
},
});
expect(results).toHaveNoViolations();
return results;
}

Verwenden Sie ihn in jedem Komponententest:

import { expectAccessible } from '../test/expectAccessible';
import { FormField } from './FormField';

it('ist zugänglich', async () => {
await expectAccessible(<FormField label="E-Mail" name="email" required />);
});
tipp

Führen Sie die vollständige axe-Suite vor jedem Commit mit einem npm-Skript aus. Bitten Sie Cursor: "Füge ein a11y-Skript zu package.json hinzu, das alle axe-Tests ausführt und bei Verstößen fehlschlägt." Dies verhindert, dass Regressionen jemals Ihren Hauptzweig erreichen.

KI-gestützte Zugänglichkeitskorrekturen​

Die KI von Cursor kann eine gesamte Komponentendatei scannen, Zugänglichkeitsprobleme finden und Korrekturen in einem Durchgang anwenden. Dies ist einer der wertvollsten a11y-Workflows.

Auditing einer Komponente​

Öffnen Sie eine Komponente in Cursor und führen Sie diesen Prompt im KI-Chat aus:

Auditiere diese Komponente auf WCAG 2.2 AA-Konformität. Liste jedes
Problem mit der Zeilennummer auf, erkläre, warum es fehlschlägt, und
schreibe den Code mit Korrekturen neu. Füge Kommentare hinzu, die
jede Änderung erklären.

Cursor könnte melden:

  • Zeile 12: <div onClick> ist nicht per Tastatur zugänglich. Durch <button> ersetzen.
  • Zeile 20: <img> hat kein alt-Attribut. Beschreibenden Alt-Text hinzufügen.
  • Zeile 28: Der Farbkontrast beträgt 3.1:1, unter dem Minimum von 4.5:1 für normalen Text.
  • Zeile 35: Der modale Dialog hat keine Fokusfalle. Benutzer können hinter den Dialog tabben.

Cursor wendet dann die Korrekturen an:

// Vorher
<div className="card" onClick={openDetails}>
<img src={product.image} />
<h3 style={{ color: '#999' }}>{product.name}</h3>
</div>

// Nachher
<button
className="card"
onClick={openDetails}
aria-label={`Details für ${product.name} ansehen`}
>
<img src={product.image} alt={`${product.name} Produktfoto`} />
<h3 style={{ color: '#595959' }}>{product.name}</h3>
</button>

Fokusfalle generieren​

Modale und Dialoge benötigen eine Fokusfalle, damit Tastaturbenutzer nicht durch Tabben aus dem Dialog entkommen können. Bitten Sie Cursor:

Füge eine Fokusfalle zu dieser Modal-Komponente hinzu. Bewege den
Fokus beim Öffnen zum ersten fokussierbaren Element, fange Tab und
Shift+Tab im Dialog ein und gib den Fokus beim Schließen an den
Auslöser-Button zurück.
import { useEffect, useRef } from 'react';

const FOCUSABLE = 'a[href], button:not([disabled]), input, textarea, select, [tabindex]:not([tabindex="-1"])';

export function useFocusTrap(active: boolean) {
const containerRef = useRef<HTMLDivElement>(null);

useEffect(() => {
if (!active || !containerRef.current) return;
const container = containerRef.current;
const elements = container.querySelectorAll<HTMLElement>(FOCUSABLE);
if (elements.length === 0) return;

const first = elements[0];
const last = elements[elements.length - 1];
first.focus();

const onKey = (e: KeyboardEvent) => {
if (e.key !== 'Tab') return;
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
};

container.addEventListener('keydown', onKey);
return () => container.removeEventListener('keydown', onKey);
}, [active]);

return containerRef;
}
warnung

Eine Fokusfalle ist bedeutungslos, wenn das zugrunde liegende HTML nicht per Tastatur zugänglich ist. Die Falle verwaltet nur Elemente, die tatsächlich fokussierbar sind. Wenn Ihr Dialog nur <div>-Elemente mit onClick-Handlern enthält, hat die Fokusfalle nichts zu fokussieren. Kombinieren Sie die Falle immer mit semantischen, fokussierbaren Elementen.

Screenreader-Tests​

Automatisierte Tests erkennen strukturelle Probleme, aber nur manuelle Tests mit einem Screenreader offenbaren die erlebte Erfahrung. Cursor kann Testskripte und Checklisten generieren.

Checkliste für reine Tastaturtests​

Bitten Sie Cursor, eine Tastaturtest-Checkliste zu generieren:

Erstelle eine Checkliste für reine Tastaturtests für eine Web-Anwendung,
die Navigation, Formulare, Widgets und dynamische Inhalte abdeckt.

Cursor produziert:

  1. Tabben Sie durch die Seite in logischer Reihenfolge ohne Fallen.
  2. Der Skip-Link ist das erste fokussierbare Element und springt zum Hauptinhalt.
  3. Alle interaktiven Elemente sind mit Tab und Shift+Tab erreichbar.
  4. Benutzerdefinierte Widgets (Tabs, Akkordeons) unterstützen Pfeiltasten und Pos1/Ende.
  5. Modale fangen den Fokus ein und geben ihn beim Schließen an den Auslöser zurück.
  6. Ein sichtbarer Fokusindikator ist auf jedem fokussierbaren Element vorhanden.
  7. Enter und Space aktivieren Buttons; Enter aktiviert Links.
  8. Formulare werden mit Enter auf dem Absenden-Button abgesendet.

Testen mit NVDA, JAWS und VoiceOver​

Cursor kann Testnotizen für jeden Screenreader generieren:

Schreibe einen Schnellstart-Leitfaden zum Testen meiner App mit NVDA
auf Windows, VoiceOver auf macOS und TalkBack auf Android. Schließe
die Verknüpfung zum Starten jedes Lesers ein und wie man nach
Überschrift und Landmark navigiert.

Cursor gibt eine Vergleichstabelle und einen Navigations-Spickzettel zurück, den Sie als Referenzdatei in Ihrem Projekt speichern können.

Farbkontrast und visuelles Design​

Visuelle Zugänglichkeit ist Teil des WCAG-Bildes. Zu geringer Kontrast ist eines der häufigsten Probleme.

Kontrast mit KI prüfen​

Bitten Sie Cursor, Ihre Design-Tokens zu evaluieren:

Hier sind meine Farb-Tokens in tailwind.config.js. Prüfe jedes Text-
und Hintergrundpaar gegen WCAG-AA-Kontrastverhältnisse (4.5:1 für
normalen Text, 3:1 für großen Text). Markiere Fehler und schlage
Korrekturen vor.

Cursor liest die Konfiguration, berechnet die Kontrastverhältnisse und meldet Fehler:

// tailwind.config.js-Tokens, die AA nicht bestehen
// text-gray-400 auf bg-white: 2.85:1 — FEHLER
// Korrektur: text-gray-600 (#4B5563) für 7.21:1 verwenden

Cursor aktualisiert die Konfiguration:

module.exports = {
theme: {
extend: {
colors: {
'text-secondary': '#4B5563', // war #9CA3AF, besteht jetzt AA
},
},
},
};
tipp

Verlassen Sie sich niemals allein auf Farbe, um Bedeutung zu vermitteln. Ein roter Rand um ein ungültiges Feld ist für farbenblinde Benutzer, die ebenfalls auf Screenreader angewiesen sind, unsichtbar. Kombinieren Sie Farbe immer mit Text oder einem Symbol. Bitten Sie Cursor: "Füge Text und Symbole hinzu, um Fehlerzustände neben Farbe zu vermitteln", um die Korrektur in einem gesamten Formular vorzunehmen.

Zugänglichkeit in CI​

Automatisierte a11y-Prüfungen gehören in Ihre Continuous-Integration-Pipeline. Cursor kann die Konfiguration generieren.

Lighthouse CI mit a11y-Kategorie​

Bitten Sie Cursor, Lighthouse CI hinzuzufügen:

Füge Lighthouse CI zu meinem GitHub-Actions-Workflow mit aktivierter
Zugänglichkeitskategorie und einer Mindestpunktzahl von 0.9 hinzu.
# .github/workflows/lighthouse.yml
name: Lighthouse
on: [pull_request]

jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
- run: npm run build
- name: Run Lighthouse
uses: treosh/lighthouse-ci-action@v11
with:
urls: |
http://localhost:3000
uploadArtifacts: true
configPath: .lighthouserc.json
// .lighthouserc.json
{
"ci": {
"assert": {
"assertions": {
"categories:accessibility": ["error", { "minScore": 0.9 }]
}
},
"collect": {
"startServerCommand": "npm run start",
"startServerReadyPattern": "ready",
"numberOfRuns": 3
}
}
}

Zusammenfassung der Best Practices​

Beachten Sie diese Prinzipien beim Erstellen zugänglicher Apps in Cursor:

  • Bevorzugen Sie semantisches HTML gegenüber ARIA, wann immer ein natives Element passt.
  • Beschriften Sie jede Eingabe mit einem echten <label> oder aria-label.
  • Machen Sie alles per Tastatur bedienbar; die Maus ist optional.
  • Automatisieren Sie mit axe-core in jedem Komponententest.
  • Testen Sie manuell mit mindestens einem Screenreader.
  • Behalten Sie 4.5:1 Kontrast bei normalem Text und sichtbare Fokusindikatoren bei.
  • Führen Sie a11y-Prüfungen in CI aus, damit Regressionen nie ausgeliefert werden.

Durch die Kombination von WCAG-Wissen mit dem KI-gestützten Auditing und der Codegenerierung von Cursor können Sie inklusive Schnittstellen erstellen, die für jeden funktionieren. Lassen Sie Cursor die zugängliche Auszeichnung und Tests erstellen, und überprüfen Sie dann die Ergebnisse mit echten Screenreadern, bevor Sie ausliefern.