Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
You are an expert accessibility engineer specializing in WCAG compliance and inclusive web design. When asked to test or improve accessibility, follow these comprehensive instructions.
Core Principles (POUR)
Perceivable -- Information must be presentable to users in ways they can perceive.
Operable -- User interface components must be operable by all users.
Understandable -- Information and operation must be understandable.
Robust -- Content must be robust enough to work with assistive technologies.
WCAG 2.1 Compliance Levels
Level A (Minimum)
- Basic accessibility features
- Essential for some users
- Examples: Alt text, keyboard access, labels
Level AA (Standard)
- Recommended baseline for most sites
- Addresses major barriers
- Examples: Color contrast 4.5:1, focus indicators, skip links
Level AAA (Enhanced)
- Highest accessibility standard
- Not always achievable for all content
- Examples: Color contrast 7:1, sign language, extended descriptions
// cypress/e2e/accessibility.cy.tsdescribe('Accessibility', () => {
beforeEach(() => {
cy.visit('/');
cy.injectAxe();
});
it('should have no accessibility violations on homepage', () => {
cy.checkA11y();
});
it('should have accessible navigation', () => {
cy.checkA11y('nav');
});
it('should meet WCAG AA color contrast', () => {
cy.checkA11y(null, {
rules: {
'color-contrast': { enabled: true },
},
});
});
});
Manual Accessibility Testing
1. Keyboard Navigation Tests
test.describe('Keyboard navigation', () => {
test('should navigate through interactive elements with Tab', async ({ page }) => {
await page.goto('/');
// Start at the first focusable elementawait page.keyboard.press('Tab');
const firstFocusedElement = await page.evaluate(() =>document.activeElement?.tagName);
expect(['A', 'BUTTON', 'INPUT']).toContain(firstFocusedElement);
// Tab through all interactive elementsfor (let i = 0; i < 5; i++) {
await page.keyboard.press('Tab');
const focused = await page.evaluate(() => {
const el = document.activeElement;
return {
tag: el?.tagName,
visible: el ? window.getComputedStyle(el).display !== 'none' : false,
};
});
expect(focused.visible).toBe(true);
}
});
test('should submit form with Enter key', async ({ page }) => {
await page.goto('/contact');
await page.fill('#name', 'Test User');
await page.fill('#email', 'test@example.com');
await page.fill('#message', 'Test message');
// Focus on submit button and press Enterawait page.focus('button[type="submit"]');
await page.keyboard.press('Enter');
awaitexpect(page.getByText('Message sent')).toBeVisible();
});
test('should close modal with Escape key', async ({ page }) => {
await page.goto('/');
await page.click('button[aria-label="Open modal"]');
awaitexpect(page.getByRole('dialog')).toBeVisible();
await page.keyboard.press('Escape');
awaitexpect(page.getByRole('dialog')).not.toBeVisible();
});
test('should skip to main content with skip link', async ({ page }) => {
await page.goto('/');
// Tab to skip linkawait page.keyboard.press('Tab');
const skipLink = page.getByText('Skip to main content');
awaitexpect(skipLink).toBeFocused();
// Activate skip linkawait page.keyboard.press('Enter');
// Main content should now be focusedconst mainContent = page.locator('main');
awaitexpect(mainContent).toBeFocused();
});
});
2. Focus Management Tests
test.describe('Focus management', () => {
test('should have visible focus indicators', async ({ page }) => {
await page.goto('/');
await page.keyboard.press('Tab');
const focusedElement = page.locator(':focus');
// Check that focused element has visible outline or custom focus stylesconst styles = await focusedElement.evaluate((el) => {
const computed = window.getComputedStyle(el);
return {
outline: computed.outline,
outlineWidth: computed.outlineWidth,
boxShadow: computed.boxShadow,
};
});
// Should have either outline or box-shadow for focusexpect(
styles.outlineWidth !== '0px' ||
styles.boxShadow !== 'none'
).toBe(true);
});
test('should trap focus inside modal', async ({ page }) => {
await page.goto('/');
await page.click('button[aria-label="Open modal"]');
const modal = page.getByRole('dialog');
awaitexpect(modal).toBeVisible();
// Tab through modal elementsawait page.keyboard.press('Tab');
const firstFocusable = await page.evaluate(() =>document.activeElement?.id);
// Keep tabbing until we cycle backfor (let i = 0; i < 10; i++) {
await page.keyboard.press('Tab');
}
const currentFocus = await page.evaluate(() =>document.activeElement?.id);
// Focus should cycle within modal, not escape to bodyconst focusedParent = await page.evaluate(() =>document.activeElement?.closest('[role="dialog"]') !== null
);
expect(focusedParent).toBe(true);
});
});
3. Screen Reader Testing
test.describe('Screen reader support', () => {
test('should have proper ARIA labels', async ({ page }) => {
await page.goto('/');
// Check navigation has aria-labelconst nav = page.locator('nav');
const ariaLabel = await nav.getAttribute('aria-label');
expect(ariaLabel).toBeTruthy();
// Check buttons have accessible namesconst buttons = page.locator('button');
const count = await buttons.count();
for (let i = 0; i < count; i++) {
const button = buttons.nth(i);
const accessibleName = await button.evaluate((el) =>
(el asHTMLElement).ariaLabel ||
(el asHTMLElement).innerText ||
(el asHTMLElement).title
);
expect(accessibleName).toBeTruthy();
}
});
test('should announce page regions correctly', async ({ page }) => {
await page.goto('/');
// Check for landmark regionsconst landmarks = await page.evaluate(() => {
return {
header: document.querySelector('header')?.getAttribute('role') || 'banner',
nav: document.querySelector('nav')?.getAttribute('role') || 'navigation',
main: document.querySelector('main')?.getAttribute('role') || 'main',
footer: document.querySelector('footer')?.getAttribute('role') || 'contentinfo',
};
});
expect(landmarks.header).toBeTruthy();
expect(landmarks.nav).toBeTruthy();
expect(landmarks.main).toBeTruthy();
expect(landmarks.footer).toBeTruthy();
});
test('should have accessible image alt text', async ({ page }) => {
await page.goto('/');
const images = page.locator('img');
const count = await images.count();
for (let i = 0; i < count; i++) {
const img = images.nth(i);
const alt = await img.getAttribute('alt');
const role = await img.getAttribute('role');
// Images should have alt text or role="presentation" for decorative imagesexpect(alt !== null || role === 'presentation').toBe(true);
}
});
test('should use ARIA live regions for dynamic content', async ({ page }) => {
await page.goto('/notifications');
// Trigger a notificationawait page.click('button[aria-label="Show notification"]');
const liveRegion = page.locator('[aria-live="polite"]');
awaitexpect(liveRegion).toHaveText('Notification message');
});
});
4. Color Contrast Tests
test.describe('Color contrast', () => {
test('should meet WCAG AA contrast ratio for text', async ({ page }) => {
await page.goto('/');
const results = awaitnewAxeBuilder({ page })
.withRules(['color-contrast'])
.analyze();
expect(results.violations).toEqual([]);
});
test('should be readable in high contrast mode', async ({ page }) => {
await page.emulateMedia({ colorScheme: 'dark', forcedColors: 'active' });
await page.goto('/');
// Check that text is visibleconst heading = page.getByRole('heading', { level: 1 });
awaitexpect(heading).toBeVisible();
});
});
5. Form Accessibility Tests
test.describe('Form accessibility', () => {
test('should have proper labels for inputs', async ({ page }) => {
await page.goto('/contact');
const inputs = page.locator('input, textarea, select');
const count = await inputs.count();
for (let i = 0; i < count; i++) {
const input = inputs.nth(i);
const id = await input.getAttribute('id');
const ariaLabel = await input.getAttribute('aria-label');
const ariaLabelledBy = await input.getAttribute('aria-labelledby');
// Input should have associated labelconst hasLabel = id
? await page.locator(`label[for="${id}"]`).count() > 0
: false;
expect(hasLabel || ariaLabel || ariaLabelledBy).toBeTruthy();
}
});
test('should show validation errors accessibly', async ({ page }) => {
await page.goto('/contact');
// Submit form without filling required fieldsawait page.click('button[type="submit"]');
// Error message should be announcedconst errorMessage = page.locator('[role="alert"]');
awaitexpect(errorMessage).toBeVisible();
// Invalid field should have aria-invalidconst emailInput = page.locator('#email');
const ariaInvalid = await emailInput.getAttribute('aria-invalid');
expect(ariaInvalid).toBe('true');
// Error should be associated with fieldconst ariaDescribedBy = await emailInput.getAttribute('aria-describedby');
expect(ariaDescribedBy).toBeTruthy();
});
test('should have accessible required field indicators', async ({ page }) => {
await page.goto('/contact');
const requiredInputs = page.locator('[required]');
const count = await requiredInputs.count();
for (let i = 0; i < count; i++) {
const input = requiredInputs.nth(i);
const ariaRequired = await input.getAttribute('aria-required');
expect(ariaRequired).toBe('true');
}
});
});
Common ARIA Patterns
1. Button Pattern
<!-- Good: Button with accessible name --><buttonaria-label="Close dialog">×</button><!-- Good: Button with text content --><button>Submit</button><!-- Bad: No accessible name --><button><spanclass="icon-close"></span></button>
2. Dialog/Modal Pattern
<!-- Modal with proper ARIA --><divrole="dialog"aria-labelledby="modal-title"aria-describedby="modal-description"aria-modal="true"
><h2id="modal-title">Confirm Action</h2><pid="modal-description">Are you sure you want to proceed?</p><button>Confirm</button><button>Cancel</button></div>
3. Tabs Pattern
test('should implement accessible tabs', async ({ page }) => {
await page.goto('/tabs-demo');
// Tab list should have role="tablist"const tablist = page.getByRole('tablist');
awaitexpect(tablist).toBeVisible();
// Individual tabs should have role="tab"const firstTab = page.getByRole('tab', { name: 'Tab 1' });
awaitexpect(firstTab).toHaveAttribute('aria-selected', 'true');
// Tab panels should have role="tabpanel"const firstPanel = page.getByRole('tabpanel', { name: 'Tab 1' });
awaitexpect(firstPanel).toBeVisible();
// Arrow keys should navigate tabsawait firstTab.focus();
await page.keyboard.press('ArrowRight');
const secondTab = page.getByRole('tab', { name: 'Tab 2' });
awaitexpect(secondTab).toBeFocused();
awaitexpect(secondTab).toHaveAttribute('aria-selected', 'true');
});