SuperAPI AI Directory

accessibility

Frontend & websites

View repository

Updated 10-15 23:58

About this skill

Frontend Accessibility (WCAG 2.2)

Practical accessibility for Next.js applications.

Baseline Standards (WCAG 2.2 Level AA)

1. Semantic HTML

Use native HTML elements before ARIA. Correct semantics solve most accessibility issues.

// ❌ Div soup
<div onClick={...} role="button" tabIndex={0}>Click me</div>

// ✅ Native button
<button onClick={...}>Click me</button>

// ❌ Nav as generic div
<div className="nav"><a href="/">Home</a></div>

// ✅ Use

2. Keyboard Navigation

Every interactive element must be reachable and operable via keyboard.

// Tab order — check these in order:
// 1. Do interactive elements have visible focus indicators?
// 2. Is the tab order logical (DOM order = focus order)?
// 3. Can all functionality be reached with Tab / Shift+Tab?
// 4. Can dropdowns/menus/modals be closed with Escape?

const focusRing = 'focus-visible:outline-2 focus-visible:outline-blue-500'

3. ARIA Labels

Every interactive element needs an accessible name.

// Icon buttons need labels
<button aria-label="Search">
  <SearchIcon />
</button>

// Sections need labelled landmarks
<nav aria-label="Footer navigation">...</nav>
<aside aria-label="Related articles">...</aside>

Next.js Specific Considerations

Link Components

// Links need discernible text
<Link href="/articles/1" aria-label="Read article: How to build accessible apps">
  Read more
</Link>

Image alt Text

// Decorative images: alt=""
<Image src="/bg.jpg" alt="" role="presentation" />

// Informative images: describe the content
<Image src="/chart.png" alt="Revenue chart: Q1 $10K, Q2 $15K, Q3 $12K" />

Form Validation

// Associate errors with inputs
<label htmlFor="email">Email</label>
<input
  id="email"
  aria-invalid={!!errors.email}
  aria-describedby={errors.email ? 'email-error' : undefined}
/>
{errors.email && <p id="email-error" role="alert">{errors.email}</p>}

Automated Testing

# Install axe-core Playwright integration
npm install -D @axe-core/playwright

# Run in CI as part of E2E tests
import { injectAxe, checkA11y } from 'axe-playwright'

test('homepage has no violations', async ({ page }) => {
  await page.goto('/')
  await injectAxe(page)
  await checkA11y(page, null, {
    includedImpacts: ['critical', 'serious']
  })
})

Manual Testing Checklist

  • Navigate all pages with Tab only — is everything reachable?
  • Can all actions be completed without a mouse?
  • Does every image have appropriate alt text?
  • Are focus indicators visible on all interactive elements?
  • Does zooming to 200% break layout?
  • Can forms be submitted with Enter key?
  • Do error messages have role="alert"?
  • Is color contrast ≥ 4.5:1 for normal text, ≥ 3:1 for large text?
  • Is the page navigable with a screen reader (VoiceOver / NVDA)?

Resources