/accessibility
Reviews accessibility including WCAG, ARIA, keyboard navigation. Use when junior builds forms, buttons, modals, interactive elements, or asks "is this accessible", "a11y", "screen reader".
$ npx -y skills add DanielPodolsky/ownyourcode --skill accessibility --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/accessibility
Context preview
The summary Claude sees to decide when to auto-load this skill.
Reviews accessibility including WCAG, ARIA, keyboard navigation. Use when junior builds forms, buttons, modals, interactive elements, or asks "is this accessible", "a11y", "screen reader".
SKILL.md
accessibility.SKILL.mdname: accessibility-fundamentals
description: Reviews accessibility including WCAG, ARIA, keyboard navigation. Use when junior builds forms, buttons, modals, interactive elements, or asks "is this accessible", "a11y", "screen reader".
Accessibility Fundamentals Review
> "Accessibility is not a feature, it's a requirement. If 15% of users can't use your app, you've failed 15% of users."
When to Apply
Activate this skill when:
- Reviewing JSX with buttons, links, or forms
- Seeing custom interactive components
- Forms with inputs and labels
- Navigation menus
- Modal dialogs
- Any user interaction code
---
The Accessibility Checklist
Must Have (Every Interactive Element)
- [ ] **Keyboard accessible** — All actions work with Tab + Enter/Space
- [ ] **Focus visible** — Clear visual indicator of focused element
- [ ] **Semantic elements** — `<button>` not `<div onClick>`
- [ ] **Form labels** — Every input has an associated `<label>`
- [ ] **Alt text** — Images have descriptive alt attributes
- [ ] **Sufficient contrast** — Text readable against background (4.5:1 ratio)
Should Have (Complex Interactions)
- [ ] **ARIA labels** — Icon-only buttons have `aria-label`
- [ ] **Focus trapping** — Modals trap focus until closed
- [ ] **Skip links** — "Skip to main content" for keyboard users
- [ ] **Live regions** — Dynamic content announced to screen readers
- [ ] **Error messages** — Linked to inputs with `aria-describedby`
Never Do
- [ ] **Rely on color alone** — Color should not be the only indicator
- [ ] **Remove focus outlines** — Never `outline: none` without replacement
- [ ] **Use divs for buttons** — Use semantic `<button>` or `<a>`
- [ ] **Trap users** — Always provide escape from modals/menus
---
Common Mistakes (Anti-Patterns)
1. Div as Button
// ❌ BAD: Not keyboard accessible, no semantics
<div onClick={handleClick} className="button">
Click me
</div>
// ✅ GOOD: Native button element
<button onClick={handleClick} className="button">
Click me
</button>**Why it matters:** `<div onClick>` doesn't receive keyboard focus, doesn't respond to Enter/Space, and isn't announced as a button by screen readers.
2. Missing Form Labels
// ❌ BAD: Input has no label
<input type="email" placeholder="Email" />
// ✅ GOOD: Label linked to input
<label htmlFor="email">Email</label>
<input id="email" type="email" placeholder="example@email.com" />
// ✅ ALSO GOOD: Wrapping label
<label>
Email
<input type="email" />
</label>
3. Icon-Only Buttons
// ❌ BAD: No accessible name
<button onClick={handleDelete}>
<TrashIcon />
</button>
// ✅ GOOD: ARIA label for screen readers
<button onClick={handleDelete} aria-label="Delete item">
<TrashIcon aria-hidden="true" />
</button>4. Removed Focus Styles
/* ❌ BAD: Focus invisible */
button:focus {
outline: none;
}
/* ✅ GOOD: Custom but visible focus */
button:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.6);
}
/* ✅ BEST: Use focus-visible */
button:focus-visible {
outline: 2px solid #4299e1;
outline-offset: 2px;
}5. Non-Descriptive Link Text
// ❌ BAD: "Click here" tells screen reader nothing
<p>
To read our privacy policy, <a href="/privacy">click here</a>.
</p>
// ✅ GOOD: Link text describes destination
<p>
Read our <a href="/privacy">privacy policy</a>.
</p>
6. Missing Heading Hierarchy
// ❌ BAD: Screen reader can't navigate
<div className="title">Welcome</div>
<div className="subtitle">Getting Started</div>
// ✅ GOOD: Proper headings
<h1>Welcome</h1>
<h2>Getting Started</h2>
---
Socratic Questions
Ask these instead of giving answers:
1. **Keyboard**: "Can you complete this action using only the keyboard?" 2. **Focus**: "If I tab through the page, can I see where I am?" 3. **Semantics**: "What does a screen reader announce for this element?" 4. **Labels**: "If the placeholder disappears, how do users know what to enter?" 5. **Color**: "If someone is colorblind, can they still understand this UI?" 6. **Alt Text**: "If the image doesn't load, what context is lost?"
---
Testing Accessibility
Manual Testing
1. **Keyboard test**: Navigate entire page with Tab only 2. **Focus test**: Can you always see where focus is? 3. **Zoom test**: Does layout break at 200% zoom? 4. **Screen reader**: Try VoiceOver (Mac) or NVDA (Windows)
Automated Testing
# In your test file
# Pattern: axe-core for React Testing Library
import { axe } from 'jest-axe';
it('should have no a11y violations', async () => {
const { container } = render(<YourComponent />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});---
ARIA Reference
Common ARIA Attributes
| Attribute | Use Case | |-----------|----------| | `aria-label` | Provides name for icon-only buttons | | `aria-labelledby` | Points to element with visible label | | `aria-describedby` | Points to description (error messages) | | `aria-hidden="true"` | Hides decorative icons from screen readers | | `aria-expanded` | Indicates dropdown/accordion state | | `aria-live` | Announces dynamic content changes | | `role` | Defines element's purpose (use sparingly) |
The First Rule of ARIA
> "No ARIA is better than bad ARIA."
Use semantic HTML first. Only use ARIA when HTML can't express what you need.
---
Stack-Specific Guidance
React
// Pattern: Button with accessible name
<button
onClick={handleAction}
aria-label="Close modal"
>
<XIcon aria-hidden="true" />
</button>Form Error Pattern
// Pattern: Error linked to input
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
aria-describedby={error ? "email-error" : undefined}
aria-invalid={error ? "true" : undefined}
/>
{error && (
<span id="email-error" role="alert">
{error}
</span>
)}---
Red Flags to Call Out
| Flag | Question | |------|--
Read more
name: accessibility-fundamentals description: Reviews accessibility including WCAG, ARIA, keyboard navigation. Use when junior builds forms, buttons, modals, interactive elements, or asks "is this accessible", "a11y", "screen reader".
Accessibility Fundamentals Review
> "Accessibility is not a feature, it's a requirement. If 15% of users can't use your app, you've failed 15% of users."
When to Apply
Activate this skill when:
- Reviewing JSX with buttons, links, or forms
- Seeing custom interactive components
- Forms with inputs and labels
- Navigation menus
- Modal dialogs
- Any user interaction code
---
The Accessibility Checklist
Must Have (Every Interactive Element)
- [ ] **Keyboard accessible** — All actions work with Tab + Enter/Space
- [ ] **Focus visible** — Clear visual indicator of focused element
- [ ] **Semantic elements** — `<button>` not `<div onClick>`
- [ ] **Form labels** — Every input has an associated `<label>`
- [ ] **Alt text** — Images have descriptive alt attributes
- [ ] **Sufficient contrast** — Text readable against background (4.5:1 ratio)
Should Have (Complex Interactions)
- [ ] **ARIA labels** — Icon-only buttons have `aria-label`
- [ ] **Focus trapping** — Modals trap focus until closed
- [ ] **Skip links** — "Skip to main content" for keyboard users
- [ ] **Live regions** — Dynamic content announced to screen readers
- [ ] **Error messages** — Linked to inputs with `aria-describedby`
Never Do
- [ ] **Rely on color alone** — Color should not be the only indicator
- [ ] **Remove focus outlines** — Never `outline: none` without replacement
- [ ] **Use divs for buttons** — Use semantic `<button>` or `<a>`
- [ ] **Trap users** — Always provide escape from modals/menus
---
Common Mistakes (Anti-Patterns)
1. Div as Button
// ❌ BAD: Not keyboard accessible, no semantics
<div onClick={handleClick} className="button">
Click me
</div>
// ✅ GOOD: Native button element
<button onClick={handleClick} className="button">
Click me
</button>**Why it matters:** `<div onClick>` doesn't receive keyboard focus, doesn't respond to Enter/Space, and isn't announced as a button by screen readers.
2. Missing Form Labels
// ❌ BAD: Input has no label <input type="email" placeholder="Email" /> // ✅ GOOD: Label linked to input <label htmlFor="email">Email</label> <input id="email" type="email" placeholder="example@email.com" /> // ✅ ALSO GOOD: Wrapping label <label> Email <input type="email" /> </label>
3. Icon-Only Buttons
// ❌ BAD: No accessible name
<button onClick={handleDelete}>
<TrashIcon />
</button>
// ✅ GOOD: ARIA label for screen readers
<button onClick={handleDelete} aria-label="Delete item">
<TrashIcon aria-hidden="true" />
</button>4. Removed Focus Styles
/* ❌ BAD: Focus invisible */
button:focus {
outline: none;
}
/* ✅ GOOD: Custom but visible focus */
button:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.6);
}
/* ✅ BEST: Use focus-visible */
button:focus-visible {
outline: 2px solid #4299e1;
outline-offset: 2px;
}5. Non-Descriptive Link Text
// ❌ BAD: "Click here" tells screen reader nothing <p> To read our privacy policy, <a href="/privacy">click here</a>. </p> // ✅ GOOD: Link text describes destination <p> Read our <a href="/privacy">privacy policy</a>. </p>
6. Missing Heading Hierarchy
// ❌ BAD: Screen reader can't navigate <div className="title">Welcome</div> <div className="subtitle">Getting Started</div> // ✅ GOOD: Proper headings <h1>Welcome</h1> <h2>Getting Started</h2>
---
Socratic Questions
Ask these instead of giving answers:
1. **Keyboard**: "Can you complete this action using only the keyboard?" 2. **Focus**: "If I tab through the page, can I see where I am?" 3. **Semantics**: "What does a screen reader announce for this element?" 4. **Labels**: "If the placeholder disappears, how do users know what to enter?" 5. **Color**: "If someone is colorblind, can they still understand this UI?" 6. **Alt Text**: "If the image doesn't load, what context is lost?"
---
Testing Accessibility
Manual Testing
1. **Keyboard test**: Navigate entire page with Tab only 2. **Focus test**: Can you always see where focus is? 3. **Zoom test**: Does layout break at 200% zoom? 4. **Screen reader**: Try VoiceOver (Mac) or NVDA (Windows)
Automated Testing
# In your test file
# Pattern: axe-core for React Testing Library
import { axe } from 'jest-axe';
it('should have no a11y violations', async () => {
const { container } = render(<YourComponent />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});---
ARIA Reference
Common ARIA Attributes
| Attribute | Use Case | |-----------|----------| | `aria-label` | Provides name for icon-only buttons | | `aria-labelledby` | Points to element with visible label | | `aria-describedby` | Points to description (error messages) | | `aria-hidden="true"` | Hides decorative icons from screen readers | | `aria-expanded` | Indicates dropdown/accordion state | | `aria-live` | Announces dynamic content changes | | `role` | Defines element's purpose (use sparingly) |
The First Rule of ARIA
> "No ARIA is better than bad ARIA."
Use semantic HTML first. Only use ARIA when HTML can't express what you need.
---
Stack-Specific Guidance
React
// Pattern: Button with accessible name
<button
onClick={handleAction}
aria-label="Close modal"
>
<XIcon aria-hidden="true" />
</button>Form Error Pattern
// Pattern: Error linked to input
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
aria-describedby={error ? "email-error" : undefined}
aria-invalid={error ? "true" : undefined}
/>
{error && (
<span id="email-error" role="alert">
{error}
</span>
)}---
Red Flags to Call Out
| Flag | Question | |------|--
Claude Code workflow for AI-mentored development. Work efficiently with Spec-Driven Development and the 6 Gates. Built to fight cognitive offloading — for developers using AI to grow and maintain ownership.
Repo: DanielPodolsky/ownyourcode
Other skills on ownyourcode.
- /resume-bullets
Transforms completed work into powerful resume bullet points with action verbs, technical context, and quantified impact. Use when completing tasks, updating portfolio, or preparing job applications.
Open skill - /star-stories
Transforms completed work into STAR interview stories (Situation, Task, Action, Result). Use when completing tasks, preparing for behavioral interviews, or documenting achievements.
Open skill - /backend
Reviews API design, REST conventions, and backend architecture. Use when junior builds API endpoints, Express routes, middleware, controllers, or asks "is this RESTful", "check my endpoint".
Open skill - /database
Reviews schema design, SQL queries, ORM patterns. Use when junior creates schema, writes queries, adds migrations, works with Prisma/MongoDB/PostgreSQL, or asks "is this SQL safe", "N+1", "index".
Open skill - /debugging
Guides systematic debugging through Protocol D (READ, ISOLATE, DOCS, HYPOTHESIZE, VERIFY). Use when junior says "stuck", "not working", "broken", "bug", "error", "crashed", "failing", "can't figure out", or expresses frustration. Do NOT use for general questions.
Open skill - /documentation
Guides documentation standards including READMEs, JSDoc, and code comments. Use when writing documentation, adding comments, or explaining code. Enforces "WHY not WHAT" principle.
Open skill

