Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    armanzeroeight

    accessibility-checker

    armanzeroeight/accessibility-checker
    Design
    21
    1 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Validate WCAG compliance, check screen reader support, and audit accessibility issues. Use when ensuring accessibility, fixing WCAG violations, or implementing inclusive design.

    SKILL.md

    Accessibility Checker

    Validate web accessibility and ensure WCAG compliance.

    Quick Start

    Use semantic HTML, add ARIA labels, ensure keyboard navigation, test color contrast, validate with axe or Lighthouse.

    Instructions

    WCAG Compliance Levels

    Level A (minimum):

    • Basic accessibility
    • Must meet for legal compliance

    Level AA (recommended):

    • Standard for most websites
    • Includes contrast requirements
    • Government sites requirement

    Level AAA (enhanced):

    • Highest level
    • Not required for all content
    • Best practices

    Common Accessibility Issues

    1. Missing alt text:

    // Bad
    <img src="logo.png" />
    
    // Good
    <img src="logo.png" alt="Company Logo" />
    
    // Decorative images
    <img src="decoration.png" alt="" />
    

    2. Poor color contrast:

    /* Bad: 2.5:1 contrast */
    color: #777;
    background: #fff;
    
    /* Good: 4.5:1 contrast (AA) */
    color: #595959;
    background: #fff;
    
    /* Better: 7:1 contrast (AAA) */
    color: #333;
    background: #fff;
    

    3. Missing form labels:

    // Bad
    <input type="text" placeholder="Name" />
    
    // Good
    <label htmlFor="name">Name</label>
    <input type="text" id="name" />
    
    // Or with aria-label
    <input type="text" aria-label="Name" />
    

    4. No keyboard navigation:

    // Bad: onClick on div
    <div onClick={handleClick}>Click me</div>
    
    // Good: Use button
    <button onClick={handleClick}>Click me</button>
    
    // Or make div focusable
    <div
      role="button"
      tabIndex={0}
      onClick={handleClick}
      onKeyPress={(e) => e.key === 'Enter' && handleClick()}
    >
      Click me
    </div>
    

    5. Missing ARIA labels:

    // Bad: Icon button without label
    <button><CloseIcon /></button>
    
    // Good: Add aria-label
    <button aria-label="Close dialog">
      <CloseIcon />
    </button>
    

    Semantic HTML

    Use proper elements:

    // Bad
    <div onClick={handleClick}>Submit</div>
    
    // Good
    <button onClick={handleClick}>Submit</button>
    
    // Bad
    <div className="heading">Title</div>
    
    // Good
    <h1>Title</h1>
    

    Heading hierarchy:

    // Bad: Skipping levels
    <h1>Page Title</h1>
    <h3>Section</h3>
    
    // Good: Proper hierarchy
    <h1>Page Title</h1>
    <h2>Section</h2>
    <h3>Subsection</h3>
    

    Landmarks:

    <header>
      <nav aria-label="Main navigation">
        {/* Navigation links */}
      </nav>
    </header>
    
    <main>
      <article>
        {/* Main content */}
      </article>
      <aside>
        {/* Sidebar */}
      </aside>
    </main>
    
    <footer>
      {/* Footer content */}
    </footer>
    

    ARIA Attributes

    aria-label:

    <button aria-label="Close">
      <X />
    </button>
    

    aria-labelledby:

    <h2 id="dialog-title">Confirm Action</h2>
    <div role="dialog" aria-labelledby="dialog-title">
      {/* Dialog content */}
    </div>
    

    aria-describedby:

    <input
      type="password"
      aria-describedby="password-hint"
    />
    <span id="password-hint">
      Must be at least 8 characters
    </span>
    

    aria-live:

    // Announce updates to screen readers
    <div aria-live="polite" aria-atomic="true">
      {statusMessage}
    </div>
    
    // For urgent updates
    <div aria-live="assertive">
      {errorMessage}
    </div>
    

    aria-expanded:

    <button
      aria-expanded={isOpen}
      aria-controls="menu"
      onClick={toggleMenu}
    >
      Menu
    </button>
    <div id="menu" hidden={!isOpen}>
      {/* Menu items */}
    </div>
    

    Keyboard Navigation

    Tab order:

    // Use tabIndex to control focus order
    <button tabIndex={0}>First</button>
    <button tabIndex={0}>Second</button>
    <button tabIndex={-1}>Not in tab order</button>
    

    Focus management:

    function Dialog({ onClose }) {
      const closeButtonRef = useRef();
      
      useEffect(() => {
        // Focus close button when dialog opens
        closeButtonRef.current?.focus();
        
        // Trap focus in dialog
        const handleTab = (e) => {
          if (e.key === 'Tab') {
            // Implement focus trap
          }
        };
        
        document.addEventListener('keydown', handleTab);
        return () => document.removeEventListener('keydown', handleTab);
      }, []);
      
      return (
        <div role="dialog" aria-modal="true">
          <button ref={closeButtonRef} onClick={onClose}>
            Close
          </button>
        </div>
      );
    }
    

    Keyboard shortcuts:

    useEffect(() => {
      const handleKeyPress = (e) => {
        if (e.key === 'Escape') {
          closeDialog();
        }
        if (e.key === '/' && e.ctrlKey) {
          openSearch();
        }
      };
      
      document.addEventListener('keydown', handleKeyPress);
      return () => document.removeEventListener('keydown', handleKeyPress);
    }, []);
    

    Screen Reader Support

    Skip links:

    <a href="#main-content" className="skip-link">
      Skip to main content
    </a>
    
    <main id="main-content">
      {/* Content */}
    </main>
    
    // CSS
    .skip-link {
      position: absolute;
      top: -40px;
      left: 0;
      background: #000;
      color: #fff;
      padding: 8px;
      z-index: 100;
    }
    
    .skip-link:focus {
      top: 0;
    }
    

    Visually hidden text:

    // CSS
    .sr-only {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: -1px;
      overflow: hidden;
      clip: rect(0, 0, 0, 0);
      white-space: nowrap;
      border-width: 0;
    }
    
    // Usage
    <button>
      <TrashIcon />
      <span className="sr-only">Delete item</span>
    </button>
    

    Announce dynamic content:

    function Toast({ message }) {
      return (
        <div
          role="status"
          aria-live="polite"
          aria-atomic="true"
        >
          {message}
        </div>
      );
    }
    

    Color Contrast

    Check contrast ratios:

    • Normal text: 4.5:1 (AA), 7:1 (AAA)
    • Large text (18pt+): 3:1 (AA), 4.5:1 (AAA)
    • UI components: 3:1

    Tools:

    • WebAIM Contrast Checker
    • Chrome DevTools
    • Lighthouse

    Don't rely on color alone:

    // Bad: Only color indicates error
    <input style={{ borderColor: 'red' }} />
    
    // Good: Color + icon + text
    <div>
      <input aria-invalid="true" aria-describedby="error" />
      <span id="error">
        <ErrorIcon /> Email is required
      </span>
    </div>
    

    Forms Accessibility

    Labels:

    <label htmlFor="email">Email</label>
    <input
      type="email"
      id="email"
      required
      aria-required="true"
    />
    

    Error messages:

    <input
      type="email"
      aria-invalid={hasError}
      aria-describedby={hasError ? "email-error" : undefined}
    />
    {hasError && (
      <span id="email-error" role="alert">
        Please enter a valid email
      </span>
    )}
    

    Fieldsets:

    <fieldset>
      <legend>Shipping Address</legend>
      <label htmlFor="street">Street</label>
      <input type="text" id="street" />
    </fieldset>
    

    Testing Tools

    Automated testing:

    # Install axe-core
    npm install --save-dev @axe-core/react
    
    # Use in tests
    import { axe, toHaveNoViolations } from 'jest-axe';
    expect.extend(toHaveNoViolations);
    
    test('should have no accessibility violations', async () => {
      const { container } = render(<MyComponent />);
      const results = await axe(container);
      expect(results).toHaveNoViolations();
    });
    

    Browser extensions:

    • axe DevTools
    • WAVE
    • Lighthouse

    Screen readers:

    • NVDA (Windows, free)
    • JAWS (Windows)
    • VoiceOver (Mac, built-in)
    • TalkBack (Android)

    Common Patterns

    Modal dialog:

    function Modal({ isOpen, onClose, title, children }) {
      const modalRef = useRef();
      
      useEffect(() => {
        if (isOpen) {
          modalRef.current?.focus();
          document.body.style.overflow = 'hidden';
        }
        return () => {
          document.body.style.overflow = '';
        };
      }, [isOpen]);
      
      if (!isOpen) return null;
      
      return (
        <div
          role="dialog"
          aria-modal="true"
          aria-labelledby="modal-title"
          ref={modalRef}
          tabIndex={-1}
        >
          <h2 id="modal-title">{title}</h2>
          {children}
          <button onClick={onClose} aria-label="Close dialog">
            Close
          </button>
        </div>
      );
    }
    

    Dropdown menu:

    function Dropdown({ label, items }) {
      const [isOpen, setIsOpen] = useState(false);
      
      return (
        <div>
          <button
            aria-haspopup="true"
            aria-expanded={isOpen}
            onClick={() => setIsOpen(!isOpen)}
          >
            {label}
          </button>
          {isOpen && (
            <ul role="menu">
              {items.map(item => (
                <li key={item.id} role="menuitem">
                  <button onClick={item.onClick}>
                    {item.label}
                  </button>
                </li>
              ))}
            </ul>
          )}
        </div>
      );
    }
    

    Tabs:

    function Tabs({ tabs }) {
      const [activeTab, setActiveTab] = useState(0);
      
      return (
        <div>
          <div role="tablist">
            {tabs.map((tab, index) => (
              <button
                key={tab.id}
                role="tab"
                aria-selected={activeTab === index}
                aria-controls={`panel-${tab.id}`}
                onClick={() => setActiveTab(index)}
              >
                {tab.label}
              </button>
            ))}
          </div>
          {tabs.map((tab, index) => (
            <div
              key={tab.id}
              role="tabpanel"
              id={`panel-${tab.id}`}
              hidden={activeTab !== index}
            >
              {tab.content}
            </div>
          ))}
        </div>
      );
    }
    

    Accessibility Checklist

    Perceivable:

    • All images have alt text
    • Color contrast meets WCAG AA (4.5:1)
    • Text can be resized to 200%
    • Content is not conveyed by color alone

    Operable:

    • All functionality available via keyboard
    • No keyboard traps
    • Skip links provided
    • Focus indicators visible

    Understandable:

    • Page language specified
    • Labels for form inputs
    • Error messages clear
    • Consistent navigation

    Robust:

    • Valid HTML
    • ARIA used correctly
    • Works with assistive technologies
    • No console errors

    Best Practices

    Start accessible:

    • Use semantic HTML first
    • Add ARIA only when needed
    • Test with keyboard
    • Test with screen reader

    Progressive enhancement:

    • Core functionality works without JS
    • Enhanced experience with JS
    • Graceful degradation

    Regular testing:

    • Automated tests (axe)
    • Manual keyboard testing
    • Screen reader testing
    • User testing with disabled users
    Recommended Servers
    vastlint - IAB XML VAST validator and linter
    vastlint - IAB XML VAST validator and linter
    AurelianFlo
    AurelianFlo
    Bizfile MCP — Global Company Intelligence
    Bizfile MCP — Global Company Intelligence
    Repository
    armanzeroeight/fastagent-plugins
    Files