---
name: standards-accessibility
description: Build accessible user interfaces using semantic HTML, proper ARIA attributes, keyboard navigation, color contrast, and screen reader compatibility. Use this skill when creating or modifying frontend components, HTML templates, React/Vue/Svelte components, forms, interactive elements, navigation menus, modals, or any UI elements. Apply when working with HTML files, JSX/TSX components, template files, ensuring keyboard accessibility, implementing focus management, adding alt text to images, creating form labels, testing with screen readers, managing ARIA attributes, maintaining color contrast ratios, or building heading hierarchies. Use for any task involving UI accessibility compliance, WCAG standards, or inclusive design patterns.
---
# Accessibility Standards
**Core Rule:** Build accessible interfaces that work for all users, including those using assistive technologies.
## When to use this skill
- When creating or modifying frontend components (React, Vue, Svelte, web components, etc.)
- When writing HTML templates or JSX/TSX component markup
- When implementing forms and ensuring all inputs have proper labels
- When adding images and needing to provide descriptive alt text
- When building interactive elements that need keyboard navigation support
- When implementing focus management in modals, dialogs, or single-page applications
- When ensuring color contrast ratios meet WCAG standards (4.5:1 for normal text)
- When adding ARIA attributes to enhance complex component accessibility
- When creating proper heading hierarchies (h1-h6) for document structure
- When testing components with screen readers or accessibility testing tools
- When building navigation menus, buttons, or links that need to be keyboard accessible
This Skill provides Claude Code with specific guidance on how to adhere to coding standards as they relate to how it should handle frontend accessibility.
## Semantic HTML First
Use native HTML elements that convey meaning to assistive technologies.
**Correct elements:**
```html
About
Submit
View Profile
...
```
**Avoid:**
```html
Go to page
Submit
```
**When to use each element:**
- ``: Actions (submit, open modal, toggle)
- ``: Navigation to different pages/sections
- ``: Navigation landmarks
- ``: Primary page content
- ``, ``, ``: Page structure
- ``, ``: Content grouping
## Keyboard Navigation
All interactive elements must be keyboard accessible.
**Requirements:**
- Tab key moves focus through interactive elements
- Enter/Space activates buttons and links
- Escape closes modals and dialogs
- Arrow keys navigate menus and lists (when appropriate)
- Focus indicators are clearly visible
**Implementation:**
```jsx
// Native elements are keyboard accessible by default
Click me
// Custom interactive elements need tabIndex
{
if (e.key === 'Enter' || e.key === ' ') {
handleClick();
}
}}
>
Custom button
// Focus styles must be visible
button:focus {
outline: 2px solid blue;
outline-offset: 2px;
}
```
**Never:**
- Remove focus outlines without providing alternative indicators
- Use `tabIndex` values other than 0 or -1
- Create keyboard traps (user can't escape with keyboard)
## Form Labels and Inputs
Every form input must have an associated label.
**Correct patterns:**
```html
Username
Email
Password
Must be at least 8 characters
```
**Required attributes:**
- `id` on input, matching `for` on label
- `type` attribute on inputs (text, email, password, etc.)
- `aria-label` or `aria-labelledby` when visual label isn't present
- `aria-describedby` for additional context or error messages
## Alternative Text for Images
Provide descriptive alt text that conveys the image's purpose.
**Guidelines:**
```jsx
{/* or */}
The system consists of three layers: frontend React app,
Node.js API server, and PostgreSQL database...
```
**Alt text rules:**
- Describe the content and function, not "image of"
- Keep concise (under 150 characters when possible)
- Use empty alt (`alt=""`) for purely decorative images
- Don't include "image", "picture", "photo" (screen readers announce this)
## Color Contrast
Maintain sufficient contrast ratios for readability.
**WCAG Requirements:**
- Normal text (< 18pt): 4.5:1 contrast ratio
- Large text (≥ 18pt or ≥ 14pt bold): 3:1 contrast ratio
- UI components and graphics: 3:1 contrast ratio
**Don't rely on color alone:**
```jsx
// BAD - color only
Error
// GOOD - color + icon + text
Error: Invalid email format
// BAD - color-coded status
// GOOD - color + text label
{status === 'active' ? 'Active' : 'Inactive'}
```
**Tools to verify contrast:**
- Browser DevTools (Chrome, Firefox have built-in checkers)
- WebAIM Contrast Checker
- Axe DevTools extension
## ARIA Attributes
Use ARIA to enhance semantics when HTML alone isn't sufficient.
**Common ARIA patterns:**
```jsx
// Roles for custom components
// States and properties
Menu
// Live regions for dynamic content
{statusMessage}
// Hide decorative elements
→
```
**ARIA rules:**
1. Use semantic HTML first, ARIA second
2. Don't override native semantics (`` is wrong)
3. All interactive ARIA roles need keyboard support
4. Test with actual screen readers
**Common ARIA attributes:**
- `aria-label`: Accessible name for element
- `aria-labelledby`: References element(s) that label this one
- `aria-describedby`: References element(s) that describe this one
- `aria-expanded`: Whether element is expanded (true/false)
- `aria-hidden`: Hide from assistive tech (use sparingly)
- `aria-live`: Announce dynamic content changes (polite/assertive)
## Heading Hierarchy
Use heading levels (h1-h6) in logical order to create document structure.
**Correct structure:**
```html
Page Title
Section 1
Subsection 1.1
Subsection 1.2
Section 2
Subsection 2.1
```
**Rules:**
- One `` per page (page title)
- Don't skip levels (h2 → h4 is wrong)
- Don't choose headings based on visual size (use CSS for styling)
- Headings create an outline for screen reader navigation
**Styling headings:**
```css
/* Separate semantic level from visual appearance */
h1 { font-size: 2rem; }
h2 { font-size: 1.5rem; }
/* If you need h3 to look like h1 */
.h3-large {
font-size: 2rem;
}
```
## Focus Management
Manage focus in dynamic interfaces to maintain keyboard navigation flow.
**Modal dialogs:**
```jsx
function Modal({ isOpen, onClose, children }) {
const modalRef = useRef();
useEffect(() => {
if (isOpen) {
// Save previously focused element
const previousFocus = document.activeElement;
// Move focus to modal
modalRef.current?.focus();
// Trap focus within modal
// (use library like focus-trap-react)
return () => {
// Restore focus when modal closes
previousFocus?.focus();
};
}
}, [isOpen]);
return (
{children}
Close
);
}
```
**Dynamic content:**
```jsx
// Announce content changes to screen readers
{loading ? 'Loading...' : `Loaded ${items.length} items`}
// Move focus to new content after navigation
function handlePageChange(newPage) {
loadPage(newPage);
// Focus the main heading of new content
document.querySelector('h1')?.focus();
}
```
## Verification Checklist
Before marking UI work complete:
- [ ] All interactive elements are keyboard accessible
- [ ] Focus indicators are visible on all focusable elements
- [ ] All images have appropriate alt text
- [ ] All form inputs have associated labels
- [ ] Color contrast meets WCAG standards (4.5:1 for text)
- [ ] Heading hierarchy is logical (no skipped levels)
- [ ] ARIA attributes are used correctly (if needed)
- [ ] Modals and dialogs manage focus appropriately
- [ ] No information conveyed by color alone
- [ ] Tested with keyboard navigation (Tab, Enter, Escape)
## Common Mistakes to Avoid
**Using divs/spans for buttons:**
```jsx
// BAD
Submit
// GOOD
Submit
```
**Missing form labels:**
```jsx
// BAD
// GOOD
Username
```
**Removing focus outlines:**
```css
/* BAD */
button:focus { outline: none; }
/* GOOD - provide alternative indicator */
button:focus {
outline: 2px solid blue;
outline-offset: 2px;
}
```
**Redundant ARIA:**
```jsx
// BAD - button already has button role
Click
// GOOD - use native semantics
Click
```
**Inaccessible custom components:**
```jsx
// BAD - no keyboard support
Custom button
// GOOD - full keyboard support
{
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleClick();
}
}}
>
Custom button
```
## Testing Accessibility
**Manual testing:**
1. Navigate entire interface using only keyboard
2. Verify all interactive elements are reachable and activatable
3. Check focus indicators are visible
4. Test with browser zoom at 200%
5. Use browser DevTools accessibility inspector
**Automated testing:**
- Axe DevTools browser extension
- Lighthouse accessibility audit
- WAVE browser extension
- eslint-plugin-jsx-a11y (for React)
**Screen reader testing:**
- macOS: VoiceOver (Cmd+F5)
- Windows: NVDA (free) or JAWS
- Test critical user flows with screen reader enabled
**Remember:** Automated tools catch ~30% of issues. Manual testing is essential.