smithery/agentient

web-accessibility-patterns

Web accessibility patterns including semantic HTML, ARIA attributes, and keyboard navigation. PROACTIVELY activate for: (1) using semantic HTML elements correctly, (2) adding ARIA labels for icons and dynamic content, (3) implementing keyboard navigation.

Installation

$ npx skills add smithery/agentient --skill web-accessibility-patterns

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/agentient · top by installs.

npx skills add smithery/agentient

Browse all from smithery/agentient

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.0

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 5,751 B
  • docs SUMMARY.md 331 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Web Accessibility Patterns

Semantic HTML Foundation

Use correct elements:

// GOOD
<button onClick={handleClick}>Submit</button>
<nav>...</nav>
<main>...</main>
<article>...</article>
<aside>...</aside>
<header>...</header>
<footer>...</footer>

// BAD
<div onClick={handleClick}>Submit</div>
<div className="nav">...</div>

ARIA Attributes

Icon-Only Buttons

<Button variant="ghost" size="icon" aria-label="Close dialog">
  <X size={16} />
</Button>

<Button variant="ghost" size="icon" aria-label="Open menu">
  <Menu size={16} />
</Button>

Form Fields

<div>
  <Label htmlFor="email">Email</Label>
  <Input
    id="email"
    type="email"
    aria-describedby="email-description email-error"
    aria-invalid={!!error}
    aria-required="true"
  />
  <p id="email-description" className="text-sm text-muted-foreground">
    We'll never share your email
  </p>
  {error && (
    <p id="email-error" className="text-sm text-destructive" role="alert">
      {error}
    </p>
  )}
</div>

Loading States

<div aria-live="polite" aria-busy={isLoading}>
  {isLoading ? <Skeleton /> : <Content />}
</div>

<Button disabled={isLoading} aria-disabled={isLoading}>
  {isLoading ? (
    <>
      <Loader className="animate-spin" aria-hidden="true" />
      <span className="sr-only">Loading</span>
      Submitting...
    </>
  ) : (
    'Submit'
  )}
</Button>

Expandable Content

function Accordion({ title, children, isOpen, onToggle }) {
  const contentId = useId();

  return (
    <div>
      <button
        aria-expanded={isOpen}
        aria-controls={contentId}
        onClick={onToggle}
      >
        {title}
      </button>
      <div id={contentId} hidden={!isOpen}>
        {children}
      </div>
    </div>
  );
}

Keyboard Navigation

Custom Interactive Element

<div
  role="button"
  tabIndex={0}
  onClick={handleClick}
  onKeyDown={(e) => {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault();
      handleClick();
    }
  }}
>
  Interactive element
</div>

Keyboard Trap for Modals

function Modal({ isOpen, onClose, children }) {
  const modalRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!isOpen) return;

    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'Escape') {
        onClose();
      }
    };

    // Focus trap - keep focus within modal
    const focusableElements = modalRef.current?.querySelectorAll(
      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
    );

    document.addEventListener('keydown', handleKeyDown);
    focusableElements?.[0]?.focus();

    return () => document.removeEventListener('keydown', handleKeyDown);
  }, [isOpen, onClose]);

  return (
    <div ref={modalRef} role="dialog" aria-modal="true">
      {children}
    </div>
  );
}

Focus Management

Visible Focus Styles

<Button className="
  focus-visible:outline-none
  focus-visible:ring-2
  focus-visible:ring-ring
  focus-visible:ring-offset-2
">
  Accessible focus state
</Button>

Skip Link

// Add at very top of page
<a
  href="#main-content"
  className="
    sr-only focus:not-sr-only
    focus:absolute focus:top-4 focus:left-4
    focus:z-50 focus:px-4 focus:py-2
    focus:bg-background focus:text-foreground
  "
>
  Skip to main content
</a>

// Main content target
<main id="main-content" tabIndex={-1}>
  ...
</main>

Screen Reader Only Content

// Visually hidden but announced
<span className="sr-only">Opens in new tab</span>

// Or with Tailwind
<span className="absolute w-px h-px p-0 -m-px overflow-hidden whitespace-nowrap border-0">
  Screen reader only text
</span>

Color and Contrast

// Use semantic colors that have proper contrast
<p className="text-foreground">Primary text - high contrast</p>
<p className="text-muted-foreground">Secondary text - still readable</p>

// Error states
<p className="text-destructive">Error message</p>

// Don't rely on color alone
<span className="text-destructive flex items-center gap-2">
  <AlertCircle size={16} aria-hidden="true" />
  Required field
</span>

Common ARIA Roles

Role Use Case
button Clickable non-button elements
dialog Modal dialogs
alert Important messages
status Status updates
navigation Navigation sections
tablist, tab, tabpanel Tab interfaces
menu, menuitem Dropdown menus

Anti-Patterns

  • <div onClick> instead of <button>
  • Icon without aria-label
  • Redundant aria-label on elements with text
  • Missing keyboard support for custom interactive elements
  • Removing focus outlines without replacement
  • Color as only indicator of state

Best Practices

  • Semantic HTML first
  • ARIA for icons and dynamic content
  • Keyboard navigation for all interactive elements
  • Focus visible styles
  • Proper heading hierarchy (h1 -> h2 -> h3)
  • Sufficient color contrast (4.5:1 for text)
  • Descriptive link text (not "click here")

Related Skills: shadcn-component-scaffolding, framer-motion-interactive-animation