Web Interface Guidelines Reviewer
vercel-labs/openreview
Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my…
Build WCAG 2.1 AA compliant websites with semantic HTML, proper ARIA, focus management, and screen reader support.
$ npx skills add LeoYeAI/openclaw-master-skills --skill accessibility -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install LeoYeAI/openclaw-master-skills accessibility --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/accessibility .claude/skills/accessibility && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "accessibility" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/accessibility into .claude/skills/accessibility/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "accessibility", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/accessibilityType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add LeoYeAI/openclaw-master-skills --skill accessibility -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install LeoYeAI/openclaw-master-skills accessibility --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/accessibility .agents/skills/accessibility && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "accessibility" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/accessibility into .agents/skills/accessibility/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "accessibility", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add LeoYeAI/openclaw-master-skills --skill accessibility -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install LeoYeAI/openclaw-master-skills accessibility --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/accessibility .cursor/skills/accessibility && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "accessibility" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/accessibility into .cursor/skills/accessibility/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "accessibility", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/LeoYeAI/openclaw-master-skills.git --path skills/accessibility--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add LeoYeAI/openclaw-master-skills --skill accessibility -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install LeoYeAI/openclaw-master-skills accessibility --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/accessibility .gemini/skills/accessibility && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "accessibility" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/accessibility into .gemini/skills/accessibility/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "accessibility", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install LeoYeAI/openclaw-master-skills accessibilityInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add LeoYeAI/openclaw-master-skills --skill accessibility -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/accessibility .github/skills/accessibility && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "accessibility" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/accessibility into .github/skills/accessibility/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "accessibility", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add LeoYeAI/openclaw-master-skills --skill accessibility -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install LeoYeAI/openclaw-master-skills accessibility --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/accessibility .opencode/skills/accessibility && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "accessibility" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/accessibility into .opencode/skills/accessibility/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "accessibility", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
accessibilityBuild WCAG 2.1 AA compliant websites with semantic HTML, proper ARIA, focus management, and screen reader support.
Accessibility is an agent skill from LeoYeAI/openclaw-master-skills. Build WCAG 2.1 AA compliant websites with semantic HTML, proper ARIA, focus management, and screen reader support. Includes color contrast (4.5:1 text), keyboard navigation, form labels, and live regions. Use when implementing accessible interfaces, fixing screen reader issues, keyboard navigation, or troubleshooting "focus outline missing", "aria-label required", "insufficient contrast".
Its SKILL.md is about 6.1k tokens, which your agent loads only when the skill is triggered. The skill folder holds 15 other files, including reference files (for example `.claude-plugin/plugin.json`, `README.md` and `_meta.json`).
It sits in Frontend & Design, covering Accessibility. The repository describes itself as: 🧠 Curated collection of 1209+ best OpenClaw skills — weekly updated by MyClaw.ai. The licence is MIT.
11 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit e5199b5. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are html, typescript and css).
From the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
w3.orgnvaccess.orgdeveloper.mozilla.orgwebaim.orgdeque.comFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Accessibility loads about 6.1k tokens when it runs, and up to ~24k if it reads all its reference files. Until then it costs about 102 tokens; SKILL.md has 1,617 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from LeoYeAI/openclaw-master-skills at commit e5199b5, republished under its MIT licence (© LeoYeAI). 1,617 words, ~6,146 tokens.
.claude/skills/accessibility/SKILL.md (or your agent's skills folder). This skill also uses 11 other files; get the full folder from GitHub.Status: Production Ready ✅ Last Updated: 2026-01-14 Dependencies: None (framework-agnostic) Standards: WCAG 2.1 Level AA
Choose the right element - don't use div for everything:
<!-- ❌ WRONG - divs with onClick -->
<div onclick="submit()">Submit</div>
<div onclick="navigate()">Next page</div>
<!-- ✅ CORRECT - semantic elements -->
<button type="submit">Submit</button>
<a href="/next">Next page</a>Why this matters:
Make interactive elements keyboard-accessible:
/* ❌ WRONG - removes focus outline */
button:focus { outline: none; }
/* ✅ CORRECT - custom accessible outline */
button:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
}CRITICAL:
:focus-visible to show only on keyboard focusEvery non-text element needs a text alternative:
<!-- ❌ WRONG - no alt text -->
<img src="logo.png">
<button><svg>...</svg></button>
<!-- ✅ CORRECT - proper alternatives -->
<img src="logo.png" alt="Company Name">
<button aria-label="Close dialog"><svg>...</svg></button>Decision tree for element selection:
Need clickable element?
├─ Navigates to another page? → <a href="...">
├─ Submits form? → <button type="submit">
├─ Opens dialog? → <button aria-haspopup="dialog">
└─ Other action? → <button type="button">
Grouping content?
├─ Self-contained article? → <article>
├─ Thematic section? → <section>
├─ Navigation links? → <nav>
└─ Supplementary info? → <aside>
Form element?
├─ Text input? → <input type="text">
├─ Multiple choice? → <select> or <input type="radio">
├─ Toggle? → <input type="checkbox"> or <button aria-pressed>
└─ Long text? → <textarea>See references/semantic-html.md for complete guide.
Golden rule: Use ARIA only when HTML can't express the pattern.
<!-- ❌ WRONG - unnecessary ARIA -->
<button role="button">Click me</button> <!-- Button already has role -->
<!-- ✅ CORRECT - ARIA fills semantic gap -->
<div role="dialog" aria-labelledby="title" aria-modal="true">
<h2 id="title">Confirm action</h2>
<!-- No HTML dialog yet, so role needed -->
</div>
<!-- ✅ BETTER - Use native HTML when available -->
<dialog aria-labelledby="title">
<h2 id="title">Confirm action</h2>
</dialog>Common ARIA patterns:
aria-label - When visible label doesn't existaria-labelledby - Reference existing text as labelaria-describedby - Additional descriptionaria-live - Announce dynamic updatesaria-expanded - Collapsible/expandable stateSee references/aria-patterns.md for complete patterns.
All interactive elements must be keyboard-accessible:
// Tab order management
function Dialog({ onClose }) {
const dialogRef = useRef<HTMLDivElement>(null);
const previousFocus = useRef<HTMLElement | null>(null);
useEffect(() => {
// Save previous focus
previousFocus.current = document.activeElement as HTMLElement;
// Focus first element in dialog
const firstFocusable = dialogRef.current?.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
(firstFocusable as HTMLElement)?.focus();
// Trap focus within dialog
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose();
if (e.key === 'Tab') {
// Focus trap logic here
}
};
document.addEventListener('keydown', handleKeyDown);
return () => {
document.removeEventListener('keydown', handleKeyDown);
// Restore focus on close
previousFocus.current?.focus();
};
}, [onClose]);
return <div ref={dialogRef} role="dialog">...</div>;
}Essential keyboard patterns:
See references/focus-management.md for complete patterns.
WCAG AA requirements:
/* ❌ WRONG - insufficient contrast */
:root {
--background: #ffffff;
--text: #999999; /* 2.8:1 - fails WCAG AA */
}
/* ✅ CORRECT - sufficient contrast */
:root {
--background: #ffffff;
--text: #595959; /* 4.6:1 - passes WCAG AA */
}Testing tools:
See references/color-contrast.md for complete guide.
Every form input needs a visible label:
<!-- ❌ WRONG - placeholder is not a label -->
<input type="email" placeholder="Email address">
<!-- ✅ CORRECT - proper label -->
<label for="email">Email address</label>
<input type="email" id="email" name="email" required aria-required="true">Error handling:
<label for="email">Email address</label>
<input
type="email"
id="email"
name="email"
aria-invalid="true"
aria-describedby="email-error"
>
<span id="email-error" role="alert">
Please enter a valid email address
</span>Live regions for dynamic errors:
<div role="alert" aria-live="assertive" aria-atomic="true">
Form submission failed. Please fix the errors above.
</div>See references/forms-validation.md for complete patterns.
✅ Use semantic HTML elements first (button, a, nav, article, etc.)
✅ Provide text alternatives for all non-text content
✅ Ensure 4.5:1 contrast for normal text, 3:1 for large text/UI
✅ Make all functionality keyboard accessible
✅ Test with keyboard only (unplug mouse)
✅ Test with screen reader (NVDA on Windows, VoiceOver on Mac)
✅ Use proper heading hierarchy (h1 → h2 → h3, no skipping)
✅ Label all form inputs with visible labels
✅ Provide focus indicators (never just outline: none)
✅ Use aria-live for dynamic content updates
❌ Use div with onClick instead of button
❌ Remove focus outlines without replacement
❌ Use color alone to convey information
❌ Use placeholders as labels
❌ Skip heading levels (h1 → h3)
❌ Use tabindex > 0 (messes with natural order)
❌ Add ARIA when semantic HTML exists
❌ Forget to restore focus after closing dialogs
❌ Use role="presentation" on focusable elements
❌ Create keyboard traps (no way to escape)
This skill prevents 12 documented accessibility issues:
Error: Interactive elements have no visible focus indicator Source: WCAG 2.4.7 (Focus Visible) Why It Happens: CSS reset removes default outline Prevention: Always provide custom focus-visible styles
Error: Text has less than 4.5:1 contrast ratio Source: WCAG 1.4.3 (Contrast Minimum) Why It Happens: Using light gray text on white background Prevention: Test all text colors with contrast checker
Error: Images missing alt attributes Source: WCAG 1.1.1 (Non-text Content) Why It Happens: Forgot to add or thought it was optional Prevention: Add alt="" for decorative, descriptive alt for meaningful images
Error: Interactive elements not reachable by keyboard Source: WCAG 2.1.1 (Keyboard) Why It Happens: Using div onClick instead of button Prevention: Use semantic interactive elements (button, a)
Error: Input fields missing associated labels
Source: WCAG 3.3.2 (Labels or Instructions)
Why It Happens: Using placeholder as label
Prevention: Always use <label> element with for/id association
Error: Heading hierarchy jumps from h1 to h3 Source: WCAG 1.3.1 (Info and Relationships) Why It Happens: Using headings for visual styling instead of semantics Prevention: Use headings in order, style with CSS
Error: Tab key exits dialog to background content Source: WCAG 2.4.3 (Focus Order) Why It Happens: No focus trap implementation Prevention: Implement focus trap for modal dialogs
Error: Screen reader doesn't announce updates Source: WCAG 4.1.3 (Status Messages) Why It Happens: Dynamic content added without announcement Prevention: Use aria-live="polite" or "assertive"
Error: Using only color to convey status Source: WCAG 1.4.1 (Use of Color) Why It Happens: Red text for errors without icon/text Prevention: Add icon + text label, not just color
Error: Links with "click here" or "read more" Source: WCAG 2.4.4 (Link Purpose) Why It Happens: Generic link text without context Prevention: Use descriptive link text or aria-label
Error: Video/audio auto-plays without user control Source: WCAG 1.4.2 (Audio Control) Why It Happens: Autoplay attribute without controls Prevention: Require user interaction to start media
Error: Custom select/checkbox without keyboard support Source: WCAG 4.1.2 (Name, Role, Value) Why It Happens: Building from divs without ARIA Prevention: Use native elements or implement full ARIA pattern
<html lang="en">)<span lang="es">)1. Unplug mouse or hide cursor
2. Tab through entire page
- Can you reach all interactive elements?
- Can you activate all buttons/links?
- Is focus order logical?
3. Use Enter/Space to activate
4. Use Escape to close dialogs
5. Use arrow keys in menus/tabsNVDA (Windows - Free):
VoiceOver (Mac - Built-in):
What to test:
axe DevTools (Browser extension - highly recommended):
Lighthouse (Built into Chrome):
interface DialogProps {
isOpen: boolean;
onClose: () => void;
title: string;
children: React.ReactNode;
}
function Dialog({ isOpen, onClose, title, children }: DialogProps) {
const dialogRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!isOpen) return;
const previousFocus = document.activeElement as HTMLElement;
// Focus first focusable element
const firstFocusable = dialogRef.current?.querySelector(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
) as HTMLElement;
firstFocusable?.focus();
// Focus trap
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
onClose();
}
if (e.key === 'Tab') {
const focusableElements = dialogRef.current?.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
if (!focusableElements?.length) return;
const first = focusableElements[0] as HTMLElement;
const last = focusableElements[focusableElements.length - 1] as HTMLElement;
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
}
};
document.addEventListener('keydown', handleKeyDown);
return () => {
document.removeEventListener('keydown', handleKeyDown);
previousFocus?.focus();
};
}, [isOpen, onClose]);
if (!isOpen) return null;
return (
<>
{/* Backdrop */}
<div
className="dialog-backdrop"
onClick={onClose}
aria-hidden="true"
/>
{/* Dialog */}
<div
ref={dialogRef}
role="dialog"
aria-modal="true"
aria-labelledby="dialog-title"
className="dialog"
>
<h2 id="dialog-title">{title}</h2>
<div className="dialog-content">{children}</div>
<button onClick={onClose} aria-label="Close dialog">×</button>
</div>
</>
);
}When to use: Any modal dialog or overlay that blocks interaction with background content.
function Tabs({ tabs }: { tabs: Array<{ label: string; content: React.ReactNode }> }) {
const [activeIndex, setActiveIndex] = useState(0);
const handleKeyDown = (e: React.KeyboardEvent, index: number) => {
if (e.key === 'ArrowLeft') {
e.preventDefault();
const newIndex = index === 0 ? tabs.length - 1 : index - 1;
setActiveIndex(newIndex);
} else if (e.key === 'ArrowRight') {
e.preventDefault();
const newIndex = index === tabs.length - 1 ? 0 : index + 1;
setActiveIndex(newIndex);
} else if (e.key === 'Home') {
e.preventDefault();
setActiveIndex(0);
} else if (e.key === 'End') {
e.preventDefault();
setActiveIndex(tabs.length - 1);
}
};
return (
<div>
<div role="tablist" aria-label="Content tabs">
{tabs.map((tab, index) => (
<button
key={index}
role="tab"
aria-selected={activeIndex === index}
aria-controls={`panel-${index}`}
id={`tab-${index}`}
tabIndex={activeIndex === index ? 0 : -1}
onClick={() => setActiveIndex(index)}
onKeyDown={(e) => handleKeyDown(e, index)}
>
{tab.label}
</button>
))}
</div>
{tabs.map((tab, index) => (
<div
key={index}
role="tabpanel"
id={`panel-${index}`}
aria-labelledby={`tab-${index}`}
hidden={activeIndex !== index}
tabIndex={0}
>
{tab.content}
</div>
))}
</div>
);
}When to use: Tabbed interface with multiple panels.
<!-- Place at very top of body -->
<a href="#main-content" class="skip-link">
Skip to main content
</a>
<style>
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: var(--primary);
color: white;
padding: 8px 16px;
z-index: 9999;
}
.skip-link:focus {
top: 0;
}
</style>
<!-- Then in your layout -->
<main id="main-content" tabindex="-1">
<!-- Page content -->
</main>When to use: All multi-page websites with navigation/header before main content.
function ContactForm() {
const [errors, setErrors] = useState<Record<string, string>>({});
const [touched, setTouched] = useState<Record<string, boolean>>({});
const validateEmail = (email: string) => {
if (!email) return 'Email is required';
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) return 'Email is invalid';
return '';
};
const handleBlur = (field: string, value: string) => {
setTouched(prev => ({ ...prev, [field]: true }));
const error = validateEmail(value);
setErrors(prev => ({ ...prev, [field]: error }));
};
return (
<form>
<div>
<label htmlFor="email">Email address *</label>
<input
type="email"
id="email"
name="email"
required
aria-required="true"
aria-invalid={touched.email && !!errors.email}
aria-describedby={errors.email ? 'email-error' : undefined}
onBlur={(e) => handleBlur('email', e.target.value)}
/>
{touched.email && errors.email && (
<span id="email-error" role="alert" className="error">
{errors.email}
</span>
)}
</div>
<button type="submit">Submit</button>
{/* Global form error */}
<div role="alert" aria-live="assertive" aria-atomic="true">
{/* Dynamic error message appears here */}
</div>
</form>
);
}When to use: All forms with validation.
Detailed documentation for deep dives:
When Claude should load these:
When to use: Request accessibility audit of existing page/component.
Three politeness levels:
<!-- Polite: Wait for screen reader to finish current announcement -->
<div aria-live="polite">New messages: 3</div>
<!-- Assertive: Interrupt immediately -->
<div aria-live="assertive" role="alert">
Error: Form submission failed
</div>
<!-- Off: Don't announce (default) -->
<div aria-live="off">Loading...</div>Best practices:
polite for non-critical updates (notifications, counters)assertive for errors and critical alertsaria-atomic="true" to read entire region on changeReact Router doesn't reset focus on navigation - you need to handle it:
function App() {
const location = useLocation();
const mainRef = useRef<HTMLElement>(null);
useEffect(() => {
// Focus main content on route change
mainRef.current?.focus();
// Announce page title to screen readers
const title = document.title;
const announcement = document.createElement('div');
announcement.setAttribute('role', 'status');
announcement.setAttribute('aria-live', 'polite');
announcement.textContent = `Navigated to ${title}`;
document.body.appendChild(announcement);
setTimeout(() => announcement.remove(), 1000);
}, [location.pathname]);
return <main ref={mainRef} tabIndex={-1} id="main-content">...</main>;
}<table>
<caption>Monthly sales by region</caption>
<thead>
<tr>
<th scope="col">Region</th>
<th scope="col">Q1</th>
<th scope="col">Q2</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">North</th>
<td>$10,000</td>
<td>$12,000</td>
</tr>
</tbody>
</table>Key attributes:
<caption> - Describes table purposescope="col" - Identifies column headersscope="row" - Identifies row headersSymptoms: Can tab through page but don't see where focus is Cause: CSS removed outlines or insufficient contrast Solution:
*:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
}Symptoms: Dynamic content changes but no announcement
Cause: No aria-live region
Solution: Wrap dynamic content in <div aria-live="polite"> or use role="alert"
Symptoms: Tab key navigates to elements behind dialog Cause: No focus trap Solution: Implement focus trap (see Pattern 1 above)
Symptoms: Visual errors appear but screen reader doesn't notice Cause: No aria-invalid or role="alert" Solution: Use aria-invalid + aria-describedby pointing to error message with role="alert"
Use this for every page/component:
<html lang="en"> or appropriate languageQuestions? Issues?
references/wcag-checklist.md for complete requirements/a11y-auditor agent to scan your pageStandards: WCAG 2.1 Level AA Testing Tools: axe DevTools, Lighthouse, NVDA, VoiceOver Success Criteria: 90+ Lighthouse score, 0 critical violations
© LeoYeAI, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 11 other files (references) in skills/accessibility of LeoYeAI/openclaw-master-skills.
Open the folder on GitHubat commit e5199b5
Accessibility next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Accessibility this skillLeoYeAI/openclaw-master-skills | 2.2k | — | ~6.1k | Automated safety check: Pass | MIT | |
| Web Interface Guidelines Reviewervercel-labs/openreview | 1.7k | 98 repos | ~308 | Automated safety check: Pass | None | |
| Accessibility Reviewmarkmead/hyperui | 12k | 1 repos | ~1.1k | Automated safety check: Pass | MIT | |
| Web Animation DesignbaptisteArno/typebot.io | 11k | 2 repos | ~2.7k | Automated safety check: Pass | Custom licence | |
| Accessibility Fixeribelick/ui-skills | 9.5k | 4 repos | ~1.2k | Automated safety check: Pass | MIT | |
| Wcag Audit PatternsvmDeshpande/ai-agent-automation | 178 | 11 repos | ~610 | Automated safety check: Pass | Apache-2.0 |
vercel-labs/openreview
Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my…
markmead/hyperui
Run a WCAG 2.1 AA accessibility audit on a design or page. An agent skill from markmead/hyperui.
baptisteArno/typebot.io
Guides easing, timing and animation choices for UI motion, based on a web animation course, and reviews existing animations in a before-and-after table.
ibelick/ui-skills
Audits and fixes HTML accessibility problems such as ARIA labels, keyboard navigation, focus management, contrast and form errors with minimal changes.
vmDeshpande/ai-agent-automation
Conduct WCAG 2.2 accessibility audits with automated testing, manual verification, and remediation guidance.
ibelick/ui-skills
Applies a fixed set of UI rules for stack, components, interaction, animation, typography and layout, or reviews a file against them with concrete fixes.
LeoYeAI/openclaw-master-skills
Manages pipelines on a DevOps quality and efficiency platform through its OpenAPI: list workspaces and templates, create, update, run and cancel pipelines, and read run records.
LeoYeAI/openclaw-master-skills
Patches OpenClaw's Feishu extension so an edited document triggers an isolated agent session that reads the doc and replies inline, turning it into a live chat space.
LeoYeAI/openclaw-master-skills
Multi-context memory management system for OpenClaw agents with group-isolated storage, global shared memory, workspace organization, and group-specific skills isolation.
LeoYeAI/openclaw-master-skills
Runs a brand's AI-search visibility work end to end: diagnosing how AI platforms represent it, repositioning it, producing AI-optimized content and monitoring ongoing mentions.
LeoYeAI/openclaw-master-skills
Installs and authenticates the gws CLI, then automates Gmail, Drive, Sheets, Calendar, Docs, Chat and Tasks with ready-made recipes, persona bundles and security audits.
LeoYeAI/openclaw-master-skills
Runs four advisor roles, a fitness coach, nutritionist, data analyst and TCM practitioner, to build a health profile and track workouts, diet and wellness over time.
Categories
Build WCAG 2.1 AA compliant websites with semantic HTML, proper ARIA, focus management, and screen reader support. Accessibility is an agent skill from LeoYeAI/openclaw-master-skills.1 AA compliant websites with semantic HTML, proper ARIA, focus management, and screen reader support.
Accessibility fits situations like: implementing accessible interfaces; fixing screen reader issues; keyboard navigation; troubleshooting focus outline missing.
Run `npx skills add LeoYeAI/openclaw-master-skills --skill accessibility -a claude-code`. Or copy the skill folder (skills/accessibility in LeoYeAI/openclaw-master-skills) into .claude/skills/accessibility in your project. Claude Code loads it when a task matches its description.
Run `npx skills add LeoYeAI/openclaw-master-skills --skill accessibility -a codex`. Or copy the skill folder (skills/accessibility in LeoYeAI/openclaw-master-skills) into .agents/skills/accessibility in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add LeoYeAI/openclaw-master-skills --skill accessibility -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/accessibility, .gemini/skills/accessibility, .github/skills/accessibility and .opencode/skills/accessibility in your project.
SKILL.md names no scripts, command-line tools or credentials: Accessibility is instructions for the agent only.
SKILL.md names 5 domains. As links in the text: w3.org, nvaccess.org, developer.mozilla.org, webaim.org and deque.com. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Accessibility is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 6.1k tokens (SKILL.md is roughly 25k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 18k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Accessibility: Web Interface Guidelines Reviewer (vercel-labs/openreview, 1.7k stars), Accessibility Review (markmead/hyperui, 12k stars), Web Animation Design (baptisteArno/typebot.io, 11k stars) and Accessibility Fixer (ibelick/ui-skills, 9.5k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
LeoYeAI (a GitHub user) maintains it in LeoYeAI/openclaw-master-skills, which has 2,159 GitHub stars. The repository holds 972 skills in this directory. The repository was last updated on July 20, 2026.
Source: LeoYeAI/openclaw-master-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.