skills/accessibility-checker/SKILL.md
# Accessibility Checker A skill that audits and improves web accessibility (a11y) to ensure the portfolio website is usable by everyone, including people with disabilities. ## Trigger Phrases This skill activates when the user wants to check or improve accessibility: - "check accessibility" - "audit a11y" - "fix accessibility issues" - "make it accessible" - "accessibility audit" - "check WCAG compliance" ## Instructions When this skill is invoked, perform a comprehensive accessibility audi
npx skillsauth add meraj-uddin-malik/portfolio-built-with-claudeai skills/accessibility-checkerInstall 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.
A skill that audits and improves web accessibility (a11y) to ensure the portfolio website is usable by everyone, including people with disabilities.
This skill activates when the user wants to check or improve accessibility:
When this skill is invoked, perform a comprehensive accessibility audit covering these key areas:
If the user specifies a file, read it first. Otherwise, ask which file or component needs to be audited.
Check that all text meets WCAG color contrast requirements:
WCAG AA (Minimum):
WCAG AAA (Enhanced):
/* ❌ BAD - Insufficient contrast */
.text {
color: #999999; /* Light gray */
background: #ffffff; /* White - only 2.8:1 contrast */
}
/* ✅ GOOD - Meets WCAG AA */
.text {
color: #525252; /* Dark gray */
background: #ffffff; /* White - 7.5:1 contrast */
}
/* ❌ BAD - Primary color might not have enough contrast */
.button {
color: #ffffff;
background: #4d94ff; /* Only 3.1:1 with white text */
}
/* ✅ GOOD - Use darker primary for better contrast */
.button {
color: #ffffff;
background: var(--color-primary-600); /* Better contrast */
}
Provide specific fixes for any contrast issues:
Ensure all interactive elements are keyboard accessible:
<!-- ❌ BAD - div used as button, not keyboard accessible -->
<div onclick="handleClick()">Click me</div>
<!-- ✅ GOOD - Semantic button, keyboard accessible -->
<button onclick="handleClick()">Click me</button>
<!-- ❌ BAD - No visible focus state -->
<style>
button:focus {
outline: none; /* Never do this! */
}
</style>
<!-- ✅ GOOD - Clear focus indicator -->
<style>
button:focus {
outline: 2px solid var(--color-primary-500);
outline-offset: 2px;
}
</style>
<!-- ❌ BAD - Missing skip link -->
<body>
<nav>...</nav>
<main>...</main>
</body>
<!-- ✅ GOOD - Skip link included -->
<body>
<a href="#main-content" class="skip-link">Skip to main content</a>
<nav>...</nav>
<main id="main-content">...</main>
</body>
<button>, <a>, <input>, etc.)// ✅ GOOD - Handle both click and keyboard events
button.addEventListener('click', handleAction);
button.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleAction();
}
});
<a href="#main-content" class="skip-link">Skip to main content</a>
<style>
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: var(--bg-primary);
color: var(--text-primary);
padding: var(--space-2) var(--space-4);
text-decoration: none;
border-radius: 0 0 4px 0;
z-index: 100;
}
.skip-link:focus {
top: 0;
outline: 2px solid var(--color-primary-500);
outline-offset: 2px;
}
</style>
Check for proper ARIA attributes and semantic markup:
aria-expanded, aria-hidden, aria-current, etc.<!-- ❌ BAD - Generic div without semantic meaning -->
<div class="navigation">
<div class="link">Home</div>
</div>
<!-- ✅ GOOD - Semantic HTML with proper roles -->
<nav role="navigation" aria-label="Main navigation">
<a href="#home">Home</a>
</nav>
<!-- ❌ BAD - Icon button without label -->
<button class="theme-toggle">
🌙
</button>
<!-- ✅ GOOD - Icon button with aria-label -->
<button class="theme-toggle" aria-label="Toggle dark mode">
<span aria-hidden="true">🌙</span>
</button>
<!-- ❌ BAD - Improper heading hierarchy -->
<h1>Page Title</h1>
<h3>Section Title</h3> <!-- Skipped H2! -->
<!-- ✅ GOOD - Proper heading hierarchy -->
<h1>Page Title</h1>
<h2>Section Title</h2>
<h3>Subsection Title</h3>
<!-- ❌ BAD - Input without label -->
<input type="email" placeholder="Email">
<!-- ✅ GOOD - Input with proper label -->
<label for="email">Email Address</label>
<input type="email" id="email" placeholder="[email protected]">
<!-- ❌ BAD - Decorative image with alt text -->
<img src="decorative-pattern.svg" alt="Decorative pattern">
<!-- ✅ GOOD - Decorative image with empty alt -->
<img src="decorative-pattern.svg" alt="">
<!-- OR use aria-hidden for purely decorative images -->
<img src="decorative-pattern.svg" aria-hidden="true" alt="">
<button role="heading"> is wrong<!-- ✅ GOOD - Proper landmark structure -->
<header role="banner">
<nav role="navigation" aria-label="Main navigation">...</nav>
</header>
<main role="main" id="main-content">
<section aria-labelledby="projects-title">
<h2 id="projects-title">Projects</h2>
...
</section>
</main>
<aside role="complementary" aria-label="Related links">...</aside>
<footer role="contentinfo">...</footer>
<!-- ✅ GOOD - Accessible form with all necessary attributes -->
<form>
<div class="form-group">
<label for="name">
Name <span aria-label="required">*</span>
</label>
<input
type="text"
id="name"
name="name"
required
aria-required="true"
aria-describedby="name-hint"
>
<span id="name-hint" class="form-hint">Enter your full name</span>
</div>
<div class="form-group">
<label for="email">Email</label>
<input
type="email"
id="email"
name="email"
aria-describedby="email-error"
aria-invalid="false"
>
<span id="email-error" class="error" role="alert"></span>
</div>
<fieldset>
<legend>Preferred Contact Method</legend>
<label>
<input type="radio" name="contact" value="email"> Email
</label>
<label>
<input type="radio" name="contact" value="phone"> Phone
</label>
</fieldset>
<button type="submit">Send Message</button>
</form>
Ensure the site works well with screen readers:
aria-hidden for decorative elementsaria-live for dynamic contentlang attribute is set<!-- ❌ BAD - Non-descriptive link text -->
<a href="/project1">Click here</a>
<!-- ✅ GOOD - Descriptive link text -->
<a href="/project1">View E-commerce Platform project</a>
<!-- ❌ BAD - Image without alt text -->
<img src="project-screenshot.jpg">
<!-- ✅ GOOD - Descriptive alt text -->
<img src="project-screenshot.jpg" alt="E-commerce platform homepage showing product grid and navigation">
<!-- ❌ BAD - Icon used for meaning without label -->
<button>
<svg>...</svg>
</button>
<!-- ✅ GOOD - Icon with descriptive label -->
<button aria-label="Open menu">
<svg aria-hidden="true">...</svg>
</button>
<!-- ❌ BAD - No language attribute -->
<html>
<!-- ✅ GOOD - Language specified -->
<html lang="en">
<!-- ❌ BAD - Dynamic content without announcement -->
<div id="notifications"></div>
<!-- ✅ GOOD - Dynamic content with live region -->
<div id="notifications" role="status" aria-live="polite" aria-atomic="true"></div>
alt="" for purely decorative images<button> for actions, <a> for navigation// ✅ GOOD - Announce dynamic content to screen readers
function showNotification(message) {
const notification = document.getElementById('notification');
notification.textContent = message;
notification.setAttribute('role', 'status');
notification.setAttribute('aria-live', 'polite');
}
// ✅ GOOD - Announce form errors
function showError(inputId, errorMessage) {
const input = document.getElementById(inputId);
const errorSpan = document.getElementById(`${inputId}-error`);
input.setAttribute('aria-invalid', 'true');
errorSpan.textContent = errorMessage;
errorSpan.setAttribute('role', 'alert');
// Focus the input for keyboard users
input.focus();
}
After auditing, provide a structured report:
## Accessibility Audit Report
### Summary
- Issues found: [number]
- WCAG Level: [AA/AAA]
- Severity: [Critical/High/Medium/Low]
### Color Contrast Issues
1. [Component] - [Issue description]
- Current: [current values]
- Fix: [recommended fix]
### Keyboard Navigation Issues
1. [Component] - [Issue description]
- Fix: [recommended fix]
### ARIA & Semantic HTML Issues
1. [Component] - [Issue description]
- Fix: [recommended fix]
### Screen Reader Issues
1. [Component] - [Issue description]
- Fix: [recommended fix]
### Recommended Actions
1. [Priority 1 - Critical fixes]
2. [Priority 2 - Important fixes]
3. [Priority 3 - Nice-to-have improvements]
For each issue found, provide the specific code fixes:
Use this comprehensive checklist for audits:
<header>, <nav>, <main>, <footer>)<html lang="en">)<label> element with for attributearia-label or aria-labelledby used appropriatelyaria-describedby used for additional contextaria-hidden used for decorative contentaria-live used for dynamic contentRecommend using these tools for accessibility testing:
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title">
<div class="modal-overlay"></div>
<div class="modal-content">
<h2 id="modal-title">Modal Title</h2>
<button class="modal-close" aria-label="Close modal">×</button>
<p>Modal content...</p>
<button>Confirm</button>
<button>Cancel</button>
</div>
</div>
<script>
// Trap focus within modal
function trapFocus(modal) {
const focusableElements = modal.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
modal.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === firstElement) {
e.preventDefault();
lastElement.focus();
} else if (!e.shiftKey && document.activeElement === lastElement) {
e.preventDefault();
firstElement.focus();
}
}
if (e.key === 'Escape') {
closeModal();
}
});
}
</script>
<nav>
<button
aria-expanded="false"
aria-controls="dropdown-menu"
aria-haspopup="true"
>
Menu
</button>
<ul id="dropdown-menu" role="menu" hidden>
<li role="none">
<a href="#" role="menuitem">Item 1</a>
</li>
<li role="none">
<a href="#" role="menuitem">Item 2</a>
</li>
</ul>
</nav>
<script>
button.addEventListener('click', () => {
const isExpanded = button.getAttribute('aria-expanded') === 'true';
button.setAttribute('aria-expanded', !isExpanded);
menu.hidden = isExpanded;
});
</script>
<div class="tabs">
<div role="tablist" aria-label="Project categories">
<button role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1">
All
</button>
<button role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2" tabindex="-1">
Web Apps
</button>
<button role="tab" aria-selected="false" aria-controls="panel-3" id="tab-3" tabindex="-1">
Mobile
</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">
Content for All...
</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>
Content for Web Apps...
</div>
<div role="tabpanel" id="panel-3" aria-labelledby="tab-3" hidden>
Content for Mobile...
</div>
</div>
development
# UI/UX Designer A skill that helps design beautiful, accessible UI components following the established design system. ## Trigger Phrases This skill activates when the user wants to design UI components: - "design a component" - "create a button/card/form" - "make this look better" - "design UI for" - "help me design" - "build a UI component" ## Instructions When this skill is invoked, follow these steps to create beautiful, accessible UI components: ### Step 1: Understand the Component R
tools
# Skill Creator A meta-skill that helps you create new skills for your portfolio website project. ## Trigger Phrases This skill activates when the user wants to create a new skill: - "create a new skill" - "make a skill" - "generate a skill" - "help me create a skill" - "add a new skill" ## Instructions When this skill is invoked, follow these steps to help the user create a new skill: ### Step 1: Gather Skill Information Use the AskUserQuestion tool to gather the following information:
development
# SEO Optimization A skill that helps optimize the portfolio website for search engines, ensuring better visibility, ranking, and performance. ## Trigger Phrases This skill activates when the user wants to optimize for SEO: - "optimize SEO" - "add meta tags" - "improve search ranking" - "check SEO" - "make it SEO friendly" - "optimize for Google" ## Instructions When this skill is invoked, follow these steps to optimize the portfolio website for search engines: ### Step 1: Audit Current SE
development
# Playwright Testing A skill that uses the browsing-with-playwright skill to visually test the portfolio website, take screenshots, check responsive design, and verify UI across different devices and viewports. ## Trigger Phrases This skill activates when the user wants to test the website visually: - "test the website" - "take screenshots" - "check responsive design" - "test on mobile/desktop" - "test responsive layout" - "visual regression test" - "check UI on different devices" ## Instruc