Accessibility Expert
---
name: "Accessibility Expert"
description: Tests and remediates accessibility issues for WCAG compliance and assistive technology compatibility. Use when (1) auditing UI for accessibility violations, (2) implementing keyboard navigation or screen reader support, (3) fixing color contrast or focus indicator issues, (4) ensuring form accessibility and error handling, (5) creating ARIA implementations.
---
# Accessibility Testing and Remediation
## Configuration
- **WCAG Level**: ${wcag_level:AA}
- **Target Component**: ${component_name:Application}
- **Compliance Standard**: ${compliance_standard:WCAG 2.1}
- **Testing Scope**: ${testing_scope:full-audit}
- **Screen Reader**: ${screen_reader:NVDA}
## WCAG 2.1 Quick Reference
### Compliance Levels
| Level | Requirement | Common Issues |
|-------|-------------|---------------|
| A | Minimum baseline | Missing alt text, no keyboard access, missing form labels |
| ${wcag_level:AA} | Standard target | Contrast < 4.5:1, missing focus indicators, poor heading structure |
| AAA | Enhanced | Contrast < 7:1, sign language, extended audio description |
### Four Principles (POUR)
1. **Perceivable**: Content available to senses (alt text, captions, contrast)
2. **Operable**: UI navigable by all input methods (keyboard, touch, voice)
3. **Understandable**: Content and UI predictable and readable
4. **Robust**: Works with current and future assistive technologies
## Violation Severity Matrix
```
CRITICAL (fix immediately):
- No keyboard access to interactive elements
- Missing form labels
- Images without alt text
- Auto-playing audio without controls
- Keyboard traps
HIGH (fix before release):
- Contrast ratio below ${min_contrast_ratio:4.5}:1 (text) or 3:1 (large text)
- Missing skip links
- Incorrect heading hierarchy
- Focus not visible
- Missing error identification
MEDIUM (fix in next sprint):
- Inconsistent navigation
- Missing landmarks
- Poor link text ("click here")
- Missing language attribute
- Complex tables without headers
LOW (backlog):
- Timing adjustments
- Multiple ways to find content
- Context-sensitive help
```
## Testing Decision Tree
```
Start: What are you testing?
|
+-- New Component
| +-- Has interactive elements? --> Keyboard Navigation Checklist
| +-- Has text content? --> Check contrast + heading structure
| +-- Has images? --> Verify alt text appropriateness
| +-- Has forms? --> Form Accessibility Checklist
|
+-- Existing Page/Feature
| +-- Run automated scan first (axe-core, Lighthouse)
| +-- Manual keyboard walkthrough
| +-- Screen reader verification
| +-- Color contrast spot-check
|
+-- Third-party Widget
+-- Check ARIA implementation
+-- Verify keyboard support
+-- Test with screen reader
+-- Document limitations
```
## Keyboard Navigation Checklist
```markdown
[ ] All interactive elements reachable via Tab
[ ] Tab order follows visual/logical flow
[ ] Focus indicator visible (${focus_indicator_width:2}px+ outline, 3:1 contrast)
[ ] No keyboard traps (can Tab out of all elements)
[ ] Skip link as first focusable element
[ ] Enter activates buttons and links
[ ] Space activates checkboxes and buttons
[ ] Arrow keys navigate within components (tabs, menus, radio groups)
[ ] Escape closes modals and dropdowns
[ ] Modals trap focus until dismissed
```
## Screen Reader Testing Patterns
### Essential Announcements to Verify
```
Interactive Elements:
Button: "[label], button"
Link: "[text], link"
Checkbox: "[label], checkbox, [checked/unchecked]"
Radio: "[label], radio button, [selected], [position] of [total]"
Combobox: "[label], combobox, [collapsed/expanded]"
Dynamic Content:
Loading: Use aria-busy="true" on container
Status: Use role="status" for non-critical updates
Alert: Use role="alert" for critical messages
Live regions: aria-live="${aria_live_politeness:polite}"
Forms:
Required: "required" announced with label
Invalid: "invalid entry" with error message
Instructions: Announced with label via aria-describedby
```
### Testing Sequence
1. Navigate entire page with Tab key, listening to announcements
2. Test headings navigation (H key in screen reader)
3. Test landmark navigation (D key / rotor)
4. Test tables (T key, arrow keys within table)
5. Test forms (F key, complete form submission)
6. Test dynamic content updates (verify live regions)
## Color Contrast Requirements
| Text Type | Minimum Ratio | Enhanced (AAA) |
|-----------|---------------|----------------|
| Normal text (<${large_text_threshold:18}pt) | ${min_contrast_ratio:4.5}:1 | 7:1 |
| Large text (>=${large_text_threshold:18}pt or 14pt bold) | 3:1 | 4.5:1 |
| UI components & graphics | 3:1 | N/A |
| Focus indicators | 3:1 | N/A |
### Contrast Check Process
```
1. Identify all foreground/background color pairs
2. Calculate contrast ratio: (L1 + 0.05) / (L2 + 0.05)
where L1 = lighter luminance, L2 = darker luminance
3. Common failures to check:
- Placeholder text (often too light)
- Disabled state (exempt but consider usability)
- Links within text (must distinguish from text)
- Error/success states on colored backgrounds
- Text over images (use overlay or text shadow)
```
## ARIA Implementation Guide
### First Rule of ARIA
Use native HTML elements when possible. ARIA is for custom widgets only.
```html
<!-- WRONG: ARIA on native element -->
<div role="button" tabindex="0">Submit</div>
<!-- RIGHT: Native button -->
<button type="submit">Submit</button>
```
### When ARIA is Needed
```html
<!-- Custom tabs -->
<div role="tablist">
<button role="tab" aria-selected="true" aria-controls="panel1">Tab 1</button>
<button role="tab" aria-selected="false" aria-controls="panel2">Tab 2</button>
</div>
<div role="tabpanel" id="panel1">Content 1</div>
<div role="tabpanel" id="panel2" hidden>Content 2</div>
<!-- Expandable section -->
<button aria-expanded="false" aria-controls="content">Show details</button>
<div id="content" hidden>Expandable content</div>
<!-- Modal dialog -->
<div role="dialog" aria-modal="true" aria-labelledby="title">
<h2 id="title">Dialog Title</h2>
<!-- content -->
</div>
<!-- Live region for dynamic updates -->
<div aria-live="${aria_live_politeness:polite}" aria-atomic="true">
<!-- Status messages injected here -->
</div>
```
### Common ARIA Mistakes
```
- role="button" without keyboard support (Enter/Space)
- aria-label duplicating visible text
- aria-hidden="true" on focusable elements
- Missing aria-expanded on disclosure buttons
- Incorrect aria-controls reference
- Using aria-describedby for essential information
```
## Form Accessibility Patterns
### Required Form Structure
```html
<form>
<!-- Explicit label association -->
<label for="email">Email address</label>
<input type="email" id="email" name="email"
aria-required="true"
aria-describedby="email-hint email-error">
<span id="email-hint">We'll never share your email</span>
<span id="email-error" role="alert"></span>
<!-- Group related fields -->
<fieldset>
<legend>Shipping address</legend>
<!-- address fields -->
</fieldset>
<!-- Clear submit button -->
<button type="submit">Complete order</button>
</form>
```
### Error Handling Requirements
```
1. Identify the field in error (highlight + icon)
2. Describe the error in text (not just color)
3. Associate error with field (aria-describedby)
4. Announce error to screen readers (role="alert")
5. Move focus to first error on submit failure
6. Provide correction suggestions when possible
```
## Mobile Accessibility Checklist
```markdown
Touch Targets:
[ ] Minimum ${touch_target_size:44}x${touch_target_size:44} CSS pixels
[ ] Adequate spacing between targets (${touch_target_spacing:8}px+)
[ ] Touch action not dependent on gesture path
Gestures:
[ ] Alternative to multi-finger gestures
[ ] Alternative to path-based gestures (swipe)
[ ] Motion-based actions have alternatives
Screen Reader (iOS/Android):
[ ] accessibilityLabel set for images and icons
[ ] accessibilityHint for complex interactions
[ ] accessibilityRole matches element behavior
[ ] Focus order follows visual layout
```
## Automated Testing Integration
### Pre-commit Hook
```bash
#!/bin/bash
# Run axe-core on changed files
npx axe-core-cli --exit src/**/*.html
# Check for common issues
grep -r "onClick.*div\|onClick.*span" src/ && \
echo "Warning: Click handler on non-interactive element" && exit 1
```
### CI Pipeline Checks
```yaml
accessibility-audit:
script:
- npx pa11y-ci --config .pa11yci.json
- npx lighthouse --accessibility --output=json
artifacts:
paths:
- accessibility-report.json
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
```
### Minimum CI Thresholds
```
axe-core: 0 critical violations, 0 serious violations
Lighthouse accessibility: >= ${lighthouse_a11y_threshold:90}
pa11y: 0 errors (warnings acceptable)
```
## Remediation Priority Framework
```
Priority 1 (This Sprint):
- Blocks user task completion
- Legal compliance risk
- Affects many users
Priority 2 (Next Sprint):
- Degrades experience significantly
- Automated tools flag as error
- Violates ${wcag_level:AA} requirement
Priority 3 (Backlog):
- Minor inconvenience
- Violates AAA only
- Affects edge cases
Priority 4 (Enhancement):
- Improves usability for all
- Best practice, not requirement
- Future-proofing
```
## Verification Checklist
Before marking accessibility work complete:
```markdown
Automated:
[ ] axe-core: 0 violations
[ ] Lighthouse accessibility: ${lighthouse_a11y_threshold:90}+
[ ] HTML validation passes
[ ] No console accessibility warnings
Keyboard:
[ ] Complete all tasks keyboard-only
[ ] Focus visible at all times
[ ] Tab order logical
[ ] No keyboard traps
Screen Reader (test with at least one):
[ ] All content announced
[ ] Interactive elements labeled
[ ] Errors and updates announced
[ ] Navigation efficient
Visual:
[ ] All text passes contrast
[ ] UI components pass contrast
[ ] Works at ${zoom_level:200}% zoom
[ ] Works in high contrast mode
[ ] No seizure-inducing flashing
Forms:
[ ] All fields labeled
[ ] Errors identifiable
[ ] Required fields indicated
[ ] Instructions available
```
## Documentation Template
```markdown
# Accessibility Statement
## Conformance Status
This [website/application] is [fully/partially] conformant with ${compliance_standard:WCAG 2.1} Level ${wcag_level:AA}.
## Known Limitations
| Feature | Issue | Workaround | Timeline |
|---------|-------|------------|----------|
| [Feature] | [Description] | [Alternative] | [Fix date] |
## Assistive Technology Tested
- ${screen_reader:NVDA} [version] with Firefox [version]
- VoiceOver with Safari [version]
- JAWS [version] with Chrome [version]
## Feedback
Contact [email] for accessibility issues.
Last updated: [date]
```
Ankara Night Scene in a Meyhane
Ultra-realistic, slightly comedic night scene in a small, slightly shabby Ankara meyhane or neighborhood bar, vertical framing as if shot on a normal phone. The interior is lit with warm yellow bulbs and a bright **blue Efes Pilsen neon sign** on the wall, which casts a cool glow. Simple wooden tables, mismatched chairs, tiled floor, walls covered in old framed photos and football scarves.
At one small table near the front, a 27-year-old Turkish-looking curvy blonde woman sits sideways on a chair, one elbow on the table, phone in her hand. She wears casual but slightly dressy clothes for a night out: fitted jeans and a low-cut but tasteful top, maybe with a light jacket hanging on the chair. Her blonde hair is loose, a bit tousled. In front of her on the table there are two **Efes Pilsen bottles**, one mostly empty and the other half full, plus a small glass of beer poured from the bottle, with bubbles and foam. Next to the bottles are a plate of meze (white cheese, cucumber, tomato), a few slices of lemon, and a bowl of nuts.
She is looking at her phone with a tired satisfied expression, thumb hovering above the screen as she finishes an “iyi geceler” tweet before heading home. The screen glow hits her face with a soft bluish tint that contrasts with the warm overhead lighting.
Around her, the bar is alive with typical Ankara characters: a group of men at a corner table laughing loudly with **Efes Draft barrel-shaped cans** and small glasses in front of them; another table with a couple sharing a plate of fries; an older bartender behind the counter drying glasses. Behind the bar, shelves hold rows of **Efes Pilsen**, **Efes Malt**, maybe a couple of **Efes Özel Seri** bottles, labels clearly visible but not arranged like a slick ad, just a real bar stock. An old fridge behind the counter has a glowing **Efes** logo on top and condensation on the glass door.
In the background there might be a muted TV showing highlights from a match or music videos. A small printed menu stuck to the wall lists “Efes Pilsen, Efes Draft, Efes Malt, Efes Xtra” in Turkish, slightly crooked. Ashtrays on tables have the Efes logo, some overflowing with cigarette butts, but smoke is subtle and realistic, not stylized.
The handheld vertical frame cuts off part of the neon sign at the top and part of another table at the edge, adding to the candid feel. There is mild motion blur on a waiter walking past and visible grain/noise in the darker corners. Colors are natural: warm skin tones, blue from the neon and labels, yellowish interior light. No beauty smoothing—her skin shows pores and little imperfections. The entire mise-en-scène feels like the end of a real Ankara bar night, captured in the moment she tells Twitter “iyi geceler” with an Efes bottle in front of her.
Beach Walk Golden Hour (full-body, travel)
{
"category": "BEACH_WALK_GOLDEN_HOUR_FULLBODY",
"subject": {
"demographics": "Adult woman, 21-29, Turkish-looking, travel influencer vibe.",
"hair": {
"color": "Dark brown",
"style": "Loose waves, wind-touched",
"texture": "Natural strands, flyaways",
"movement": "Hair moving lightly with sea breeze"
},
"face": {
"eyes": "Happy, squinting slightly in sun",
"skin_details": "Realistic texture, sun-kissed glow (not oily)",
"makeup": "Minimal beach look"
},
"clothing": {
"outfit": "Linen dress or beach cover-up (no logos)",
"fabric": "Linen weave visible, gentle wrinkles",
"movement": "Dress hem moving naturally"
},
"accessories": {
"jewelry": ["Silver hoops"]
}
},
"pose": {
"type": "Full-body walking candid",
"orientation": "Mid-step along shoreline",
"hands": "One hand holding dress hem, other brushing hair back",
"gaze": "Looking down laughing, then glancing toward camera vibe",
"posture": "Carefree, relaxed"
},
"setting": {
"environment": "Beach shoreline",
"background_elements": [
"Soft sunset reflections on water",
"Footprints in sand",
"Subtle haze (natural sea air, not smoke)"
],
"depth": "Subject sharp, background softly blurred"
},
"camera": {
"shot_type": "Full-body travel photo",
"angle": "Eye-level",
"focal_length_equivalent": "26mm phone or 35mm editorial",
"framing": "4:5",
"focus": "Face readable; motion blur minimal"
},
"lighting": {
"source": "Golden hour sunlight",
"direction": "Back/side rim light on hair and shoulders",
"highlights": "Controlled sun flare",
"shadows": "Soft, warm"
},
"mood_and_expression": {
"tone": "Dreamy, carefree, warm",
"expression": "Natural laughter",
"atmosphere": "Wanderlust candid"
},
"style_and_realism": {
"style": "Photoreal travel influencer",
"imperfections": "Slight motion blur on dress hem allowed; face stays detailed"
},
"technical_details": {
"aspect_ratio": "4:5",
"noise": "Low to mild",
"motion_blur": "Subtle in fabric only"
},
"constraints": {
"adult_only": true,
"no_text": true,
"no_logos": true,
"no_watermarks": true
},
"negative_prompt": [
"watergun splash", "fake water texture",
"extra limbs", "warped horizon",
"readable text", "logos", "watermark"
]
}
Cinematic Neo-Noir Triptych in Digital Art
{
"colors": {
"color_temperature": "cool",
"contrast_level": "high",
"dominant_palette": [
"teal",
"cyan",
"dark blue",
"black",
"orange"
]
},
"composition": {
"camera_angle": "multiple",
"depth_of_field": "shallow",
"focus": "A solitary man",
"framing": "The image is a triptych, a sequence of three cinematic panels. The top panel is a wide shot of a man from behind, the middle is a close-up portrait, and the bottom is a medium shot. This creates a film strip or storyboard effect."
},
"description_short": "A cinematic triptych showing a lone man in a dark, moody city at night. The scenes depict him walking on a wet street, a pensive close-up of his face, and him lighting a cigarette.",
"environment": {
"location_type": "cityscape",
"setting_details": "A modern city at night with tall buildings, neon signs, and traffic lights. The streets are wet and reflective, suggesting recent rain. The scenes take place on a crosswalk, a sidewalk, and possibly under an overpass.",
"time_of_day": "night",
"weather": "rainy"
},
"lighting": {
"intensity": "moderate",
"source_direction": "mixed",
"type": "cinematic"
},
"mood": {
"atmosphere": "Lonely and contemplative urban noir",
"emotional_tone": "melancholic"
},
"narrative_elements": {
"character_interactions": "The man is depicted alone, suggesting themes of isolation and introspection.",
"environmental_storytelling": "The dark, rainy, and empty city streets amplify the character's solitude and the moody, mysterious atmosphere of a neo-noir film.",
"implied_action": "The sequence of shots—walking, pausing to think, lighting a cigarette—suggests the character is contemplating something significant or is in a moment of crisis or decision."
},
"objects": [
"man",
"dark coat",
"messenger bag",
"wet street",
"crosswalk",
"city buildings",
"neon signs",
"traffic lights",
"lighter"
],
"people": {
"ages": [
"adult"
],
"clothing_style": "dark overcoat",
"count": "1",
"genders": [
"male"
]
},
"prompt": "Cinematic film stills in a triptych format, neo-noir style. A solitary man in his late 30s walks through a rain-slicked city street at night. The city is bathed in cool teal and blue tones from ambient light, contrasted with warm orange and yellow from neon signs and traffic lights, which reflect on the wet pavement. The first panel is a wide shot from behind, the second a tight, emotional close-up of his face, and the third shows him lighting a cigarette under an overpass. Moody, atmospheric, shallow depth of field, high contrast.",
"style": {
"art_style": "cinematic",
"influences": [
"neo-noir",
"cyberpunk",
"Blade Runner"
],
"medium": "digital art"
},
"technical_tags": [
"triptych",
"film still",
"neo-noir",
"color grading",
"teal and orange",
"cinematic lighting",
"night photography",
"wet reflections",
"bokeh"
],
"use_case": "Dataset for training AI in cinematic storytelling, mood generation, and neo-noir style replication.",
"uuid": "7c21100c-8de4-4687-8952-5de3ac5e42b3"
}
Editorial Winter Poster–Style Multi-Panel Collage Generation
{
"meta_protocols": {
"reference_adherence": {
"instruction": "Use the provided male face photo as a strict reference_image.",
"tolerance": "Zero deviation",
"parameters": "Preserve exact male facial proportions, skin texture, expression, age, and identity with 100% accuracy.",
"stylization_constraint": "Do not beautify, feminize, or alter facial features in any way."
},
"format_style": "Editorial winter poster–style multi-panel collage",
"aesthetic_quality": "Spontaneous iPhone photography (candid, cozy, realistic)",
"global_textures": "Soft snowfall, subtle analog grain, slight handheld imperfections"
},
"consistent_elements": {
"subject_wardrobe": {
"outerwear": "Black tailored wool overcoat",
"top": "Thick knit sweater (dark neutral tone)",
"bottom": "Classic fabric trousers",
"footwear": "Winter leather boots",
"style_notes": "Masculine, elegant, understated winter style"
},
"primary_device": {
"model": "iPhone 17 Pro Max",
"color": "Silver",
"usage": "Held by subject in relevant frames"
},
"color_palette": [
"Warm ambers",
"Charcoal blacks",
"Deep browns",
"Muted winter greys"
]
},
"layout_configuration": {
"panel_1_top_left": {
"scene_type": "Reflective shop-window shot on a winter street at dusk",
"lighting_and_atmosphere": "Street lamps, faint holiday lights, cold air condensation, warm highlights on coat fabric",
"subject_action": "Holding phone partially covering face",
"optical_effects": "Passing pedestrians as blurred silhouettes, layered reflections, natural glass distortion",
"mood": "Quiet, introspective, urban masculinity"
},
"panel_2_top_right": {
"scene_type": "Parisian café exterior portrait",
"location_detail": "Outdoor table at a Paris street café",
"camera_angle": "Close, slightly low angle for masculine presence",
"subject_pose": "Seated confidently, relaxed posture, one arm resting on the table",
"action": "Holding a whiskey glass mid-sip",
"wardrobe_visibility": "Black coat open, knit sweater and fabric trousers clearly visible",
"motion_dynamics": "Light snow falling, background pedestrians softly motion-blurred",
"lens_characteristics": "Natural handheld perspective with subtle depth compression"
},
"panel_3_bottom_right": {
"scene_type": "Intimate overhead selfie on a city sidewalk",
"lighting": "Warm street lighting contrasting cold night air",
"props": {
"held_item": "Takeaway coffee cup",
"accessories": "Wired earphones visible"
},
"texture_focus": "Detailed wool coat texture, knit sweater fibers, subtle skin grain",
"mood": "Lonely, reflective winter night energy"
}
},
"graphic_overlay": {
"element": "Minimal Spotify–style mini player",
"content": "Flying - Anathema",
"style": "Flat, clean UI, no shadows",
"position": "Floating subtly across the center of the collage"
}
}