
Frontend Accessibility
- 516 installs
- 305 repo stars
- Updated March 4, 2026
- aj-geddes/useful-ai-prompts
frontend-accessibility is a frontend skill that generates WCAG-compliant semantic HTML, ARIA labels, keyboard navigation, and screen reader optimizations for inclusive web applications.
About
frontend-accessibility is a skill from aj-geddes/useful-ai-prompts for building inclusive web UIs to WCAG standards. It guides implementation of semantic HTML structure, appropriate ARIA attributes, keyboard navigation patterns, and screen reader support so applications work for assistive technology users. Developers reach for frontend-accessibility when compliance is required, inclusive design is a release criterion, or existing components fail keyboard and screen reader checks. The skill includes quick-start guidance, reference guides, and best-practice checklists the agent applies while editing React, HTML, or component libraries. It fits frontend build tasks where accessibility must be designed into markup and interaction patterns, not patched after QA.
- Implements WCAG compliance using semantic HTML and ARIA attributes
- Ensures keyboard navigation and screen reader support
- Automatically audits and fixes color contrast issues
- Produces inclusive frontend components ready for production
- Works across React, Vue, plain HTML, and Tailwind projects
Frontend Accessibility by the numbers
- 516 all-time installs (skills.sh)
- Ranked #581 of 1,880 Design & UI/UX skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/aj-geddes/useful-ai-prompts --skill frontend-accessibilityAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 516 |
|---|---|
| repo stars | ★ 305 |
| Last updated | March 4, 2026 |
| Repository | aj-geddes/useful-ai-prompts ↗ |
How do you implement WCAG accessibility in React UI?
Generate WCAG-compliant semantic HTML, ARIA labels, keyboard navigation patterns, and screen reader optimizations directly in their frontend codebase.
Who is it for?
Frontend developers shipping inclusive web apps who need WCAG guidance applied directly in component code.
Skip if: Native mobile-only projects without web UI or teams needing formal third-party accessibility audit certification only.
When should I use this skill?
Building new UI components, fixing accessibility audit failures, or when compliance with WCAG and inclusive design is required.
What you get
Semantic HTML markup, ARIA labels, keyboard-navigable components, and screen-reader-optimized UI patterns.
- accessible component markup
- ARIA attribute map
- keyboard interaction patterns
Files
Frontend Accessibility
Table of Contents
Overview
Build accessible web applications following WCAG guidelines with semantic HTML, ARIA attributes, keyboard navigation, and screen reader support for inclusive user experiences.
When to Use
- Compliance with accessibility standards
- Inclusive design requirements
- Screen reader support
- Keyboard navigation
- Color contrast issues
Quick Start
Minimal working example:
<!-- Good semantic structure -->
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
<main>
<article>
<header>
<h1>Article Title</h1>
<time datetime="2024-01-15">January 15, 2024</time>
</header>
<p>Article content...</p>
</article>
<aside aria-label="Related articles">
<h2>Related Articles</h2>
<ul>
<li><a href="/article1">Article 1</a></li>
<li><a href="/article2">Article 2</a></li>
</ul>
</aside>
// ... (see reference guides for full implementation)Reference Guides
Detailed implementations in the references/ directory:
| Guide | Contents |
|---|---|
| Semantic HTML and ARIA | Semantic HTML and ARIA |
| Keyboard Navigation | Keyboard Navigation |
| Color Contrast and Visual Accessibility | Color Contrast and Visual Accessibility |
| Screen Reader Announcements | Screen Reader Announcements |
| Accessibility Testing | Accessibility Testing |
Best Practices
✅ DO
- Follow established patterns and conventions
- Write clean, maintainable code
- Add appropriate documentation
- Test thoroughly before deploying
❌ DON'T
- Skip testing or validation
- Ignore error handling
- Hard-code configuration values
Accessibility Testing
Accessibility Testing
// jest-axe integration test
import { render } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';
import { Button } from './Button';
expect.extend(toHaveNoViolations);
describe('Button Accessibility', () => {
it('should not have accessibility violations', async () => {
const { container } = render(
<Button>Click me</Button>
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('should have proper ARIA labels', async () => {
const { container } = render(
<Button aria-label="Close dialog">×</Button>
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});
// Accessibility Checker Hook
const useAccessibilityChecker = () => {
useEffect(() => {
// Run accessibility checks in development
if (process.env.NODE_ENV === 'development') {
import('axe-core').then(axe => {
axe.run((error, results) => {
if (results.violations.length > 0) {
console.warn('Accessibility violations found:', results.violations);
}
});
});
}
}, []);
};Color Contrast and Visual Accessibility
Color Contrast and Visual Accessibility
/* Proper color contrast (WCAG AA: 4.5:1 for text, 3:1 for large text) */
:root {
--color-text: #1a1a1a; /* Black - high contrast */
--color-background: #ffffff;
--color-primary: #0066cc; /* Blue with good contrast */
--color-success: #008000; /* Not pure green */
--color-error: #d32f2f; /* Not pure red */
--color-warning: #ff8c00; /* Not yellow */
}
body {
color: var(--color-text);
background-color: var(--color-background);
font-size: 16px;
line-height: 1.5;
}
a {
color: var(--color-primary);
text-decoration: underline; /* Don't rely on color alone */
}
button {
min-height: 44px; /* Touch target size */
min-width: 44px;
padding: 10px 20px;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
}
/* Focus visible for keyboard navigation */
button:focus-visible,
a:focus-visible,
input:focus-visible {
outline: 3px solid var(--color-primary);
outline-offset: 2px;
}
/* High contrast mode support */
@media (prefers-contrast: more) {
body {
font-weight: 500;
}
button {
border: 2px solid currentColor;
}
}
/* Reduced motion support */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* Dark mode support */
@media (prefers-color-scheme: dark) {
:root {
--color-text: #e0e0e0;
--color-background: #1a1a1a;
--color-primary: #6495ed;
}
}Keyboard Navigation
Keyboard Navigation
// React Component with keyboard support
import React, { useEffect, useRef, useState } from 'react';
interface MenuItem {
id: string;
label: string;
href: string;
}
const KeyboardNavigationMenu: React.FC<{ items: MenuItem[] }> = ({ items }) => {
const [activeIndex, setActiveIndex] = useState(0);
const menuRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
switch (e.key) {
case 'ArrowLeft':
case 'ArrowUp':
e.preventDefault();
setActiveIndex(prev =>
prev === 0 ? items.length - 1 : prev - 1
);
break;
case 'ArrowRight':
case 'ArrowDown':
e.preventDefault();
setActiveIndex(prev =>
prev === items.length - 1 ? 0 : prev + 1
);
break;
case 'Home':
e.preventDefault();
setActiveIndex(0);
break;
case 'End':
e.preventDefault();
setActiveIndex(items.length - 1);
break;
case 'Enter':
case ' ':
e.preventDefault();
const link = menuRef.current?.querySelectorAll('a')[activeIndex];
link?.click();
break;
case 'Escape':
menuRef.current?.querySelector('a')?.blur();
break;
default:
break;
}
};
menuRef.current?.addEventListener('keydown', handleKeyDown);
return () => menuRef.current?.removeEventListener('keydown', handleKeyDown);
}, [items.length, activeIndex]);
return (
<div role="menubar" ref={menuRef}>
{items.map((item, index) => (
<a
key={item.id}
href={item.href}
role="menuitem"
tabIndex={index === activeIndex ? 0 : -1}
onFocus={() => setActiveIndex(index)}
aria-current={index === activeIndex ? 'page' : undefined}
>
{item.label}
</a>
))}
</div>
);
};Screen Reader Announcements
Screen Reader Announcements
// LiveRegion component for announcements
interface LiveRegionProps {
message: string;
politeness?: 'polite' | 'assertive' | 'off';
role?: 'status' | 'alert';
}
const LiveRegion: React.FC<LiveRegionProps> = ({
message,
politeness = 'polite',
role = 'status'
}) => {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (message && ref.current) {
ref.current.textContent = message;
}
}, [message]);
return (
<div
ref={ref}
role={role}
aria-live={politeness}
aria-atomic="true"
className="sr-only"
/>
);
};
// Usage in component
const SearchResults: React.FC = () => {
const [results, setResults] = useState([]);
const [message, setMessage] = useState('');
const handleSearch = async (query: string) => {
const response = await fetch(`/api/search?q=${query}`);
const data = await response.json();
setResults(data);
setMessage(`Found ${data.length} results`);
};
return (
<>
<LiveRegion message={message} />
<input
type="text"
placeholder="Search..."
onChange={(e) => handleSearch(e.target.value)}
aria-label="Search results"
/>
<ul>
{results.map(item => (
<li key={item.id}>{item.title}</li>
))}
</ul>
</>
);
};
// Skip to main content link (hidden by default)
const skipLink = document.createElement('a');
skipLink.href = '#main-content';
skipLink.textContent = 'Skip to main content';
skipLink.style.position = 'absolute';
skipLink.style.top = '-40px';
skipLink.style.left = '0';
skipLink.style.background = '#000';
skipLink.style.color = '#fff';
skipLink.style.padding = '8px';
skipLink.style.zIndex = '100';
skipLink.addEventListener('focus', () => {
skipLink.style.top = '0';
});
skipLink.addEventListener('blur', () => {
skipLink.style.top = '-40px';
});
document.body.insertBefore(skipLink, document.body.firstChild);Semantic HTML and ARIA
Semantic HTML and ARIA
<!-- Good semantic structure -->
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
<main>
<article>
<header>
<h1>Article Title</h1>
<time datetime="2024-01-15">January 15, 2024</time>
</header>
<p>Article content...</p>
</article>
<aside aria-label="Related articles">
<h2>Related Articles</h2>
<ul>
<li><a href="/article1">Article 1</a></li>
<li><a href="/article2">Article 2</a></li>
</ul>
</aside>
</main>
<footer>
<p>© 2024 Company Name</p>
</footer>
<!-- Form with proper labels -->
<form>
<div class="form-group">
<label for="email">Email Address</label>
<input
id="email"
type="email"
name="email"
required
aria-required="true"
aria-describedby="email-help"
/>
<small id="email-help">We'll never share your email</small>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
id="password"
type="password"
name="password"
required
aria-required="true"
aria-describedby="password-requirements"
/>
<div id="password-requirements">
<ul>
<li>At least 8 characters</li>
<li>One uppercase letter</li>
<li>One number</li>
</ul>
</div>
</div>
<button type="submit">Sign Up</button>
</form>
<!-- Modal with proper ARIA -->
<div
id="modal"
role="dialog"
aria-labelledby="modal-title"
aria-describedby="modal-description"
aria-modal="true"
>
<button aria-label="Close modal">×</button>
<h2 id="modal-title">Confirm Action</h2>
<p id="modal-description">Are you sure?</p>
<button>Cancel</button>
<button>Confirm</button>
</div>
<!-- Alert with role -->
<div role="alert" aria-live="polite">
<strong>Error:</strong> Please correct the highlighted fields
</div>// Component: [Name]
// TODO: Customize for your framework (React, Vue, Svelte, etc.)
import React from 'react';
interface Props {
// TODO: Define props
}
export function ComponentName({ }: Props) {
// TODO: Add state and effects
return (
<div>
{/* TODO: Add component markup */}
</div>
);
}
Related skills
FAQ
What standards does frontend-accessibility follow?
frontend-accessibility follows WCAG guidelines using semantic HTML, ARIA attributes, keyboard navigation, and screen reader support so web applications meet inclusive design and compliance requirements.
When should frontend-accessibility be invoked?
frontend-accessibility should be invoked when building new UI, remediating audit failures, or meeting inclusive design requirements where components need keyboard access and assistive technology compatibility.