skills/frontend-a11y/SKILL.md
Write minimal, accessible HTML, CSS, and JavaScript without over-engineering. Always use this skill on every project, for every task that involves writing or reviewing HTML markup, building web components, creating forms, adding interactive elements like buttons, dialogs, accordions, or tabs, or auditing code for accessibility — even when the user doesn't explicitly mention accessibility, and even when working in a framework, CMS, or design system context. This skill is non-negotiable and applies regardless of project type, stack, or deadline. If you're about to reach for ARIA attributes, a dialog library, a focus-trap package, or a headless UI component, use this skill first.
npx skillsauth add mikemai2awesome/agent-skills frontend-a11yInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Write as little code as possible. Use native HTML elements that are already accessible instead of adding ARIA attributes to generic elements.
role attributes<dialog>, <details>, <button> before reaching for JavaScriptThe browser already provides accessible elements. Use them.
<!-- Don't do this — too much code -->
<div role="button" tabindex="0" onclick="submit()">Submit</div>
<!-- Do this — native button is already accessible -->
<button type="submit">Submit</button>
Landmark elements already have implicit roles. Don't repeat them.
<!-- Don't do this -->
<header role="banner">...</header>
<nav role="navigation">...</nav>
<main role="main">...</main>
<footer role="contentinfo">...</footer>
<!-- Do nothing — the browser already handles this -->
<header>...</header>
<nav>...</nav>
<main>...</main>
<footer>...</footer>
Replace generic containers with meaningful elements.
<!-- Don't do this -->
<div class="header">
<div class="nav">...</div>
</div>
<!-- Do this -->
<header>
<nav>...</nav>
</header>
The title attribute is poorly supported. Only use it on <iframe>.
<!-- Don't do this -->
<button title="Submit form">Submit</button>
<!-- Only use title on iframe -->
<iframe src="..." title="Video player"></iframe>
Use native elements that already have the behavior you need.
Use native <details> and <summary>. No JavaScript needed.
<!-- Don't do this — too much code -->
<div class="accordion">
<button aria-expanded="false" aria-controls="panel-1">Section</button>
<div id="panel-1" hidden>Content</div>
</div>
<!-- Do this — zero JavaScript required -->
<details>
<summary>Section</summary>
<p>Content</p>
</details>
Use native <dialog> with showModal(). Focus trapping and Escape key handling are built-in.
<!-- Don't do this — requires focus trap JavaScript -->
<div role="dialog" aria-modal="true" aria-labelledby="title">
<h2 id="title">Title</h2>
<p>Content</p>
</div>
<!-- Do this — focus trap is automatic -->
<dialog id="my-dialog">
<h2>Title</h2>
<p>Content</p>
<button type="button" onclick="this.closest('dialog').close()">Close</button>
</dialog>
<button
type="button"
onclick="document.getElementById('my-dialog').showModal()"
>
Open dialog
</button>
The showModal() method automatically:
::backdrop pseudo-elementUse <nav> with <button> and aria-expanded for dropdowns.
<nav>
<ul>
<li>
<button aria-expanded="false" aria-controls="submenu">Products</button>
<ul id="submenu" hidden>
<li><a href="/product-1">Product 1</a></li>
</ul>
</li>
</ul>
</nav>
Don't use role="menu", role="menuitem", or aria-haspopup for navigation.
A single role="alert" is all you need.
<div role="alert">Your changes have been saved.</div>
The patterns below are specific to accessibility.
Don't create modifier classes when ARIA attributes already exist.
/* Don't do this — extra classes */
.accordion-header--collapsed {
}
.accordion-header--expanded {
}
/* Do this — style the ARIA state */
[aria-expanded="false"] {
}
[aria-expanded="true"] {
}
More examples:
[aria-current="page"] {
font-weight: bold;
}
[aria-disabled="true"] {
opacity: 0.6;
cursor: not-allowed;
}
[aria-selected="true"] {
background-color: highlight;
}
[aria-invalid="true"] {
border-color: red;
}
Use CSS instead so screen readers don't spell out letters.
<!-- Don't do this -->
<span>SUBMIT</span>
<!-- Do this -->
<span class="u-uppercase">Submit</span>
.u-uppercase {
text-transform: uppercase;
}
Text must meet WCAG 2.1 AA minimum contrast ratios — this is one of the most commonly failed accessibility checks. Always choose foreground/background color pairs that clear these thresholds:
Safe defaults that clear 4.5:1 without any calculation:
/* Dark text on light backgrounds */
body {
color: #404040;
background: #f4f4f4;
} /* ~9.43:1 */
.muted {
color: #636363;
background: #f4f4f4;
} /* ~5.46:1 */
/* Light text on dark backgrounds */
.dark {
color: #c9d4de;
background: #040014;
} /* ~13.75:1 */
/* Avoid these common low-contrast mistakes */
/* color: #767676 on white = exactly 4.5:1 — pass, but use sparingly */
/* color: #999 on white = 2.85:1 — FAIL */
/* color: #888 on #eee = 3.05:1 — FAIL for normal text */
Ensure all interactive elements have visible, high-contrast focus indicators.
*:focus-visible {
outline: 2px solid;
outline-offset: 2px;
}
Only apply translucent or glassy effects when the user hasn't requested reduced transparency.
@media (prefers-reduced-transparency: no-preference) {
.glass-panel {
background: oklch(100% 0 0 / 0.8);
backdrop-filter: blur(1rem);
}
}
Only animate elements when the user hasn't requested reduced motion.
@media (prefers-reduced-motion: no-preference) {
.animated-element {
transition: transform 0.3s ease;
}
}
Never use opacity: 0 alone to hide content before a fade-in animation. Screen readers ignore opacity — an element at opacity: 0 is still in the accessibility tree and will be announced before sighted users can see it.
A safe fade-in layers two protections:
<h1 class="fade-in">Welcome</h1>
@media (prefers-reduced-motion: no-preference) {
.js-ready .fade-in {
opacity: 0;
}
.fade-in.is-visible {
animation: fade-in 0.6s ease forwards;
}
}
@keyframes fade-in {
to {
opacity: 1;
}
}
document.documentElement.classList.add("js-ready");
const observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
entry.target.classList.add("is-visible");
observer.unobserve(entry.target);
}
}
});
for (const el of document.querySelectorAll(".fade-in")) {
observer.observe(el);
}
This works because:
js-ready class is never added — content stays fully visible and accessibleRead these when you need more detail than the guidelines above:
development
Implement accessibility in iOS apps using Swift, UIKit, and SwiftUI. Use this skill whenever working on any iOS development task that involves: making UI elements accessible to VoiceOver or other assistive technologies, adding or reviewing accessibility labels/hints/traits/actions/values, supporting Dynamic Type or text scaling, respecting Reduce Motion or reduced transparency preferences, adapting to Dark Mode or increased contrast, building accessible forms and inputs, announcing dynamic content changes, managing focus programmatically, customizing accessibility focus order, supporting external keyboard navigation, or auditing iOS code for accessibility issues. Trigger even when the user only says "SwiftUI" or "UIKit" without mentioning "accessibility" explicitly — if they're building custom controls, modals, forms, lists, or animated views, this skill applies.
development
Write minimal, efficient CSS for small or minimalist projects by trusting the browser instead of fighting it. Only use this skill for personal sites, prototypes, simple landing pages, or projects intentionally kept lean — if the project has multiple developers, a component library, a design token system, or more than a handful of CSS files, a more comprehensive CSS approach is needed. If you're about to write a CSS reset, declare a base font-size on :root, set default colors on body, use px for spacing, or reach for physical margin/padding properties, this skill will stop you.
development
Write scalable, well-architected CSS using design tokens, cascade layers, and modern organization patterns. Use this skill as the default for any real project — if it has more than a handful of CSS files, multiple components, a team, a design system, or any kind of token or theming setup, this is the right skill.
development
Create web interfaces with an authentic early-2010s aesthetic. Use this skill when the user wants a 2010s-era, Web 2.0, or retro corporate web look — gradient headers, glossy buttons, skeuomorphic icons, horizontal band layouts, and drop shadows from circa 2010–2014.