[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6F0Y2CNEPKF44FSFJ061PZ5":3,"skill-same:01M6F0Y2CNEPKF44FSFJ061PZ5":90},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":26,"publishedAt":47,"linkOnly":48,"markdownContent":49,"markdownBody":50,"frontMatter":51,"refName":55,"commitSha":56,"skillDirectory":57,"forksCount":58,"repositoryHtmlUrl":59,"repositoryHomepageUrl":60,"ownerHtmlUrl":61,"ownerBlogUrl":6,"ownerDescription":62,"updatedAt":63,"install":64,"resources":77},"01M6F0Y2CNEPKF44FSFJ061PZ5","web-accessibility",null,"Implement web accessibility (a11y) standards following WCAG 2.1 guidelines. Use when building accessible UIs, fixing accessibility issues, or ensuring compliance with disability standards. Handles ARIA attributes, keyboard navigation, screen readers, semantic HTML, and accessibility testing.","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fsupercent-io\u002Fweb-accessibility\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发",[27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],"web","accessibility","web accessibility","WCAG","with","screen","keyboard","accessibility testing","aria","fixing accessibility","standards","html","use","testing","compliance","chatgpt","issues","guidelines","implement","gemini","2026-11-10 10:12:30",false,"---\nname: web-accessibility\ndescription: Implement web accessibility (a11y) standards following WCAG 2.1 guidelines. Use when building accessible UIs, fixing accessibility issues, or ensuring compliance with disability standards. Handles ARIA attributes, keyboard navigation, screen readers, semantic HTML, and accessibility testing.\nmetadata:\n  tags: accessibility, a11y, WCAG, ARIA, semantic-HTML, screen-reader\n  platforms: Claude, ChatGPT, Gemini\n---\n\n\n# Web Accessibility (A11y)\n\n\n## When to use this skill\n\n- **New UI Component Development**: Designing accessible components\n- **Accessibility Audit**: Identifying and fixing accessibility issues in existing sites\n- **Form Implementation**: Writing screen reader-friendly forms\n- **Modals\u002FDropdowns**: Focus management and keyboard trap prevention\n- **WCAG Compliance**: Meeting legal requirements or standards\n\n## Input Format\n\n### Required Information\n- **Framework**: React, Vue, Svelte, Vanilla JS, etc.\n- **Component Type**: Button, Form, Modal, Dropdown, Navigation, etc.\n- **WCAG Level**: A, AA, AAA (default: AA)\n\n### Optional Information\n- **Screen Reader**: NVDA, JAWS, VoiceOver (for testing)\n- **Automated Testing Tool**: axe-core, Pa11y, Lighthouse (default: axe-core)\n- **Browser**: Chrome, Firefox, Safari (default: Chrome)\n\n### Input Example\n\n```\nMake a React modal component accessible:\n- Framework: React + TypeScript\n- WCAG Level: AA\n- Requirements:\n  - Focus trap (focus stays inside the modal)\n  - Close with ESC key\n  - Close by clicking the background\n  - Title\u002Fdescription read by screen readers\n```\n\n## Instructions\n\n### Step 1: Use Semantic HTML\n\nUse meaningful HTML elements to make the structure clear.\n\n**Tasks**:\n- Use semantic tags: `\u003Cbutton>`, `\u003Cnav>`, `\u003Cmain>`, `\u003Cheader>`, `\u003Cfooter>`, etc.\n- Avoid overusing `\u003Cdiv>` and `\u003Cspan>`\n- Use heading hierarchy (`\u003Ch1>` ~ `\u003Ch6>`) correctly\n- Connect `\u003Clabel>` with `\u003Cinput>`\n\n**Example** (❌ Bad vs ✅ Good):\n```html\n\u003C!-- ❌ Bad example: using only div and span -->\n\u003Cdiv class=\"header\">\n  \u003Cspan class=\"title\">My App\u003C\u002Fspan>\n  \u003Cdiv class=\"nav\">\n    \u003Cdiv class=\"nav-item\" onclick=\"navigate()\">Home\u003C\u002Fdiv>\n    \u003Cdiv class=\"nav-item\" onclick=\"navigate()\">About\u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\n\u003C!-- ✅ Good example: semantic HTML -->\n\u003Cheader>\n  \u003Ch1>My App\u003C\u002Fh1>\n  \u003Cnav aria-label=\"Main navigation\">\n    \u003Cul>\n      \u003Cli>\u003Ca href=\"\u002F\">Home\u003C\u002Fa>\u003C\u002Fli>\n      \u003Cli>\u003Ca href=\"\u002Fabout\">About\u003C\u002Fa>\u003C\u002Fli>\n    \u003C\u002Ful>\n  \u003C\u002Fnav>\n\u003C\u002Fheader>\n```\n\n**Form Example**:\n```html\n\u003C!-- ❌ Bad example: no label -->\n\u003Cinput type=\"text\" placeholder=\"Enter your name\">\n\n\u003C!-- ✅ Good example: label connected -->\n\u003Clabel for=\"name\">Name:\u003C\u002Flabel>\n\u003Cinput type=\"text\" id=\"name\" name=\"name\" required>\n\n\u003C!-- Or wrap with label -->\n\u003Clabel>\n  Email:\n  \u003Cinput type=\"email\" name=\"email\" required>\n\u003C\u002Flabel>\n```\n\n### Step 2: Implement Keyboard Navigation\n\nEnsure all features are usable without a mouse.\n\n**Tasks**:\n- Move focus with Tab and Shift+Tab\n- Activate buttons with Enter\u002FSpace\n- Navigate lists\u002Fmenus with arrow keys\n- Close modals\u002Fdropdowns with ESC\n- Use `tabindex` appropriately\n\n**Decision Criteria**:\n- Interactive elements → `tabindex=\"0\"` (focusable)\n- Exclude from focus order → `tabindex=\"-1\"` (programmatic focus only)\n- Do not change focus order → avoid using `tabindex=\"1+\"`\n\n**Example** (React Dropdown):\n```typescript\nimport React, { useState, useRef, useEffect } from 'react';\n\ninterface DropdownProps {\n  label: string;\n  options: { value: string; label: string }[];\n  onChange: (value: string) => void;\n}\n\nfunction AccessibleDropdown({ label, options, onChange }: DropdownProps) {\n  const [isOpen, setIsOpen] = useState(false);\n  const [selectedIndex, setSelectedIndex] = useState(0);\n  const buttonRef = useRef\u003CHTMLButtonElement>(null);\n  const listRef = useRef\u003CHTMLUListElement>(null);\n\n  \u002F\u002F Keyboard handler\n  const handleKeyDown = (e: React.KeyboardEvent) => {\n    switch (e.key) {\n      case 'ArrowDown':\n        e.preventDefault();\n        if (!isOpen) {\n          setIsOpen(true);\n        } else {\n          setSelectedIndex((prev) => (prev + 1) % options.length);\n        }\n        break;\n\n      case 'ArrowUp':\n        e.preventDefault();\n        if (!isOpen) {\n          setIsOpen(true);\n        } else {\n          setSelectedIndex((prev) => (prev - 1 + options.length) % options.length);\n        }\n        break;\n\n      case 'Enter':\n      case ' ':\n        e.preventDefault();\n        if (isOpen) {\n          onChange(options[selectedIndex].value);\n          setIsOpen(false);\n          buttonRef.current?.focus();\n        } else {\n          setIsOpen(true);\n        }\n        break;\n\n      case 'Escape':\n        e.preventDefault();\n        setIsOpen(false);\n        buttonRef.current?.focus();\n        break;\n    }\n  };\n\n  return (\n    \u003Cdiv className=\"dropdown\">\n      \u003Cbutton\n        ref={buttonRef}\n        onClick={() => setIsOpen(!isOpen)}\n        onKeyDown={handleKeyDown}\n        aria-haspopup=\"listbox\"\n        aria-expanded={isOpen}\n        aria-labelledby=\"dropdown-label\"\n      >\n        {label}\n      \u003C\u002Fbutton>\n\n      {isOpen && (\n        \u003Cul\n          ref={listRef}\n          role=\"listbox\"\n          aria-labelledby=\"dropdown-label\"\n          onKeyDown={handleKeyDown}\n          tabIndex={-1}\n        >\n          {options.map((option, index) => (\n            \u003Cli\n              key={option.value}\n              role=\"option\"\n              aria-selected={index === selectedIndex}\n              onClick={() => {\n                onChange(option.value);\n                setIsOpen(false);\n              }}\n            >\n              {option.label}\n            \u003C\u002Fli>\n          ))}\n        \u003C\u002Ful>\n      )}\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n### Step 3: Add ARIA Attributes\n\nProvide additional context for screen readers.\n\n**Tasks**:\n- `aria-label`: Define the element's name\n- `aria-labelledby`: Reference another element as a label\n- `aria-describedby`: Provide additional description\n- `aria-live`: Announce dynamic content changes\n- `aria-hidden`: Hide from screen readers\n\n**Checklist**:\n- [x] All interactive elements have clear labels\n- [x] Button purpose is clear (e.g., \"Submit form\" not \"Click\")\n- [x] State change announcements (aria-live)\n- [x] Decorative images use alt=\"\" or aria-hidden=\"true\"\n\n**Example** (Modal):\n```tsx\nfunction AccessibleModal({ isOpen, onClose, title, children }) {\n  const modalRef = useRef\u003CHTMLDivElement>(null);\n\n  \u002F\u002F Focus trap when modal opens\n  useEffect(() => {\n    if (isOpen) {\n      modalRef.current?.focus();\n    }\n  }, [isOpen]);\n\n  if (!isOpen) return null;\n\n  return (\n    \u003Cdiv\n      role=\"dialog\"\n      aria-modal=\"true\"\n      aria-labelledby=\"modal-title\"\n      aria-describedby=\"modal-description\"\n      ref={modalRef}\n      tabIndex={-1}\n      onKeyDown={(e) => {\n        if (e.key === 'Escape') {\n          onClose();\n        }\n      }}\n    >\n      \u003Cdiv className=\"modal-overlay\" onClick={onClose} aria-hidden=\"true\" \u002F>\n\n      \u003Cdiv className=\"modal-content\">\n        \u003Ch2 id=\"modal-title\">{title}\u003C\u002Fh2>\n        \u003Cdiv id=\"modal-description\">\n          {children}\n        \u003C\u002Fdiv>\n\n        \u003Cbutton onClick={onClose} aria-label=\"Close modal\">\n          \u003Cspan aria-hidden=\"true\">×\u003C\u002Fspan>\n        \u003C\u002Fbutton>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n**aria-live Example** (Notifications):\n```tsx\nfunction Notification({ message, type }: { message: string; type: 'success' | 'error' }) {\n  return (\n    \u003Cdiv\n      role=\"alert\"\n      aria-live=\"assertive\"  \u002F\u002F Immediate announcement (error), \"polite\" announces in turn\n      aria-atomic=\"true\"     \u002F\u002F Read the entire content\n      className={`notification notification-${type}`}\n    >\n      {type === 'error' && \u003Cspan aria-label=\"Error\">⚠️\u003C\u002Fspan>}\n      {type === 'success' && \u003Cspan aria-label=\"Success\">✅\u003C\u002Fspan>}\n      {message}\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n### Step 4: Color Contrast and Visual Accessibility\n\nEnsure sufficient contrast ratios for users with visual impairments.\n\n**Tasks**:\n- WCAG AA: text 4.5:1, large text 3:1\n- WCAG AAA: text 7:1, large text 4.5:1\n- Do not convey information by color alone (use icons, patterns alongside)\n- Clearly indicate focus (outline)\n\n**Example** (CSS):\n```css\n\u002F* ✅ Sufficient contrast (text #000 on #FFF = 21:1) *\u002F\n.button {\n  background-color: #0066cc;\n  color: #ffffff;  \u002F* contrast ratio 7.7:1 *\u002F\n}\n\n\u002F* ✅ Focus indicator *\u002F\nbutton:focus,\na:focus {\n  outline: 3px solid #0066cc;\n  outline-offset: 2px;\n}\n\n\u002F* ❌ outline: none is forbidden! *\u002F\nbutton:focus {\n  outline: none;  \u002F* Never use this *\u002F\n}\n\n\u002F* ✅ Indicate state with color + icon *\u002F\n.error-message {\n  color: #d32f2f;\n  border-left: 4px solid #d32f2f;\n}\n\n.error-message::before {\n  content: '⚠️';\n  margin-right: 8px;\n}\n```\n\n### Step 5: Accessibility Testing\n\nValidate accessibility with automated and manual testing.\n\n**Tasks**:\n- Automated scan with axe DevTools\n- Check Lighthouse Accessibility score\n- Test all features with keyboard only\n- Screen reader testing (NVDA, VoiceOver)\n\n**Example** (Jest + axe-core):\n```typescript\nimport { render } from '@testing-library\u002Freact';\nimport { axe, toHaveNoViolations } from 'jest-axe';\nimport AccessibleButton from '.\u002FAccessibleButton';\n\nexpect.extend(toHaveNoViolations);\n\ndescribe('AccessibleButton', () => {\n  it('should have no accessibility violations', async () => {\n    const { container } = render(\n      \u003CAccessibleButton onClick={() => {}}>\n        Click Me\n      \u003C\u002FAccessibleButton>\n    );\n\n    const results = await axe(container);\n    expect(results).toHaveNoViolations();\n  });\n\n  it('should be keyboard accessible', () => {\n    const handleClick = jest.fn();\n    const { getByRole } = render(\n      \u003CAccessibleButton onClick={handleClick}>\n        Click Me\n      \u003C\u002FAccessibleButton>\n    );\n\n    const button = getByRole('button');\n\n    \u002F\u002F Enter key\n    button.focus();\n    fireEvent.keyDown(button, { key: 'Enter' });\n    expect(handleClick).toHaveBeenCalled();\n\n    \u002F\u002F Space key\n    fireEvent.keyDown(button, { key: ' ' });\n    expect(handleClick).toHaveBeenCalledTimes(2);\n  });\n});\n```\n\n## Output format\n\n### Basic Checklist\n\n```markdown\n## Accessibility Checklist\n\n### Semantic HTML\n- [x] Use semantic HTML tags (`\u003Cbutton>`, `\u003Cnav>`, `\u003Cmain>`, etc.)\n- [x] Heading hierarchy is correct (h1 → h2 → h3)\n- [x] All form labels are connected\n\n### Keyboard Navigation\n- [x] All interactive elements accessible via Tab\n- [x] Buttons activated with Enter\u002FSpace\n- [x] Modals\u002Fdropdowns closed with ESC\n- [x] Focus indicator is clear (outline)\n\n### ARIA\n- [x] `role` used appropriately\n- [x] `aria-label` or `aria-labelledby` provided\n- [x] `aria-live` used for dynamic content\n- [x] Decorative elements use `aria-hidden=\"true\"`\n\n### Visual\n- [x] Color contrast meets WCAG AA (4.5:1)\n- [x] Information not conveyed by color alone\n- [x] Text size can be adjusted\n- [x] Responsive design\n\n### Testing\n- [x] 0 axe DevTools violations\n- [x] Lighthouse Accessibility score 90+\n- [x] Keyboard test passed\n- [x] Screen reader test completed\n```\n\n## Constraints\n\n### Mandatory Rules (MUST)\n\n1. **Keyboard Accessibility**: All features must be usable without a mouse\n   - Support Tab, Enter, Space, arrow keys, and ESC\n   - Implement focus trap (for modals)\n\n2. **Alternative Text**: All images must have an `alt` attribute\n   - Meaningful images: descriptive alt text\n   - Decorative images: `alt=\"\"` (screen reader ignores)\n\n3. **Clear Labels**: All form inputs must have an associated label\n   - `\u003Clabel for=\"...\">` or `aria-label`\n   - Do not use placeholder alone as a substitute for a label\n\n### Prohibited Actions (MUST NOT)\n\n1. **Do Not Remove Outline**: Never use `outline: none`\n   - Disastrous for keyboard users\n   - Must provide a custom focus style instead\n\n2. **Do Not Use tabindex > 0**: Avoid changing focus order\n   - Keep DOM order logical\n   - Exception: only when there is a special reason\n\n3. **Do Not Convey Information by Color Alone**: Accompany with icons or text\n   - Consider users with color blindness\n   - e.g., \"Click red item\" → \"Click ⚠️ Error item\"\n\n## Examples\n\n### Example 1: Accessible Form\n\n```tsx\nfunction AccessibleContactForm() {\n  const [errors, setErrors] = useState\u003CRecord\u003Cstring, string>>({});\n  const [submitStatus, setSubmitStatus] = useState\u003C'idle' | 'success' | 'error'>('idle');\n\n  return (\n    \u003Cform onSubmit={handleSubmit} noValidate>\n      \u003Ch2 id=\"form-title\">Contact Us\u003C\u002Fh2>\n      \u003Cp id=\"form-description\">Please fill out the form below to get in touch.\u003C\u002Fp>\n\n      {\u002F* Name *\u002F}\n      \u003Cdiv className=\"form-group\">\n        \u003Clabel htmlFor=\"name\">\n          Name \u003Cspan aria-label=\"required\">*\u003C\u002Fspan>\n        \u003C\u002Flabel>\n        \u003Cinput\n          type=\"text\"\n          id=\"name\"\n          name=\"name\"\n          required\n          aria-required=\"true\"\n          aria-invalid={!!errors.name}\n          aria-describedby={errors.name ? 'name-error' : undefined}\n        \u002F>\n        {errors.name && (\n          \u003Cspan id=\"name-error\" role=\"alert\" className=\"error\">\n            {errors.name}\n          \u003C\u002Fspan>\n        )}\n      \u003C\u002Fdiv>\n\n      {\u002F* Email *\u002F}\n      \u003Cdiv className=\"form-group\">\n        \u003Clabel htmlFor=\"email\">\n          Email \u003Cspan aria-label=\"required\">*\u003C\u002Fspan>\n        \u003C\u002Flabel>\n        \u003Cinput\n          type=\"email\"\n          id=\"email\"\n          name=\"email\"\n          required\n          aria-required=\"true\"\n          aria-invalid={!!errors.email}\n          aria-describedby={errors.email ? 'email-error' : 'email-hint'}\n        \u002F>\n        \u003Cspan id=\"email-hint\" className=\"hint\">\n          We'll never share your email.\n        \u003C\u002Fspan>\n        {errors.email && (\n          \u003Cspan id=\"email-error\" role=\"alert\" className=\"error\">\n            {errors.email}\n          \u003C\u002Fspan>\n        )}\n      \u003C\u002Fdiv>\n\n      {\u002F* Submit button *\u002F}\n      \u003Cbutton type=\"submit\" disabled={submitStatus === 'loading'}>\n        {submitStatus === 'loading' ? 'Submitting...' : 'Submit'}\n      \u003C\u002Fbutton>\n\n      {\u002F* Success\u002Ffailure messages *\u002F}\n      {submitStatus === 'success' && (\n        \u003Cdiv role=\"alert\" aria-live=\"polite\" className=\"success\">\n          ✅ Form submitted successfully!\n        \u003C\u002Fdiv>\n      )}\n\n      {submitStatus === 'error' && (\n        \u003Cdiv role=\"alert\" aria-live=\"assertive\" className=\"error\">\n          ⚠️ An error occurred. Please try again.\n        \u003C\u002Fdiv>\n      )}\n    \u003C\u002Fform>\n  );\n}\n```\n\n### Example 2: Accessible Tab UI\n\n```tsx\nfunction AccessibleTabs({ tabs }: { tabs: { id: string; label: string; content: React.ReactNode }[] }) {\n  const [activeTab, setActiveTab] = useState(0);\n\n  const handleKeyDown = (e: React.KeyboardEvent, index: number) => {\n    switch (e.key) {\n      case 'ArrowRight':\n        e.preventDefault();\n        setActiveTab((index + 1) % tabs.length);\n        break;\n      case 'ArrowLeft':\n        e.preventDefault();\n        setActiveTab((index - 1 + tabs.length) % tabs.length);\n        break;\n      case 'Home':\n        e.preventDefault();\n        setActiveTab(0);\n        break;\n      case 'End':\n        e.preventDefault();\n        setActiveTab(tabs.length - 1);\n        break;\n    }\n  };\n\n  return (\n    \u003Cdiv>\n      {\u002F* Tab List *\u002F}\n      \u003Cdiv role=\"tablist\" aria-label=\"Content sections\">\n        {tabs.map((tab, index) => (\n          \u003Cbutton\n            key={tab.id}\n            role=\"tab\"\n            id={`tab-${tab.id}`}\n            aria-selected={activeTab === index}\n            aria-controls={`panel-${tab.id}`}\n            tabIndex={activeTab === index ? 0 : -1}\n            onClick={() => setActiveTab(index)}\n            onKeyDown={(e) => handleKeyDown(e, index)}\n          >\n            {tab.label}\n          \u003C\u002Fbutton>\n        ))}\n      \u003C\u002Fdiv>\n\n      {\u002F* Tab Panels *\u002F}\n      {tabs.map((tab, index) => (\n        \u003Cdiv\n          key={tab.id}\n          role=\"tabpanel\"\n          id={`panel-${tab.id}`}\n          aria-labelledby={`tab-${tab.id}`}\n          hidden={activeTab !== index}\n          tabIndex={0}\n        >\n          {tab.content}\n        \u003C\u002Fdiv>\n      ))}\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n## Best practices\n\n1. **Semantic HTML First**: ARIA is a last resort\n   - Using the correct HTML element makes ARIA unnecessary\n   - e.g., `\u003Cbutton>` vs `\u003Cdiv role=\"button\">`\n\n2. **Focus Management**: Manage focus on page transitions in SPAs\n   - Move focus to main content on new page load\n   - Provide skip links (\"Skip to main content\")\n\n3. **Error Messages**: Clear and helpful error messages\n   - \"Invalid input\" ❌ → \"Email must be in format: example@domain.com\" ✅\n\n## References\n\n- [WCAG 2.1 Guidelines](https:\u002F\u002Fwww.w3.org\u002FWAI\u002FWCAG21\u002Fquickref\u002F)\n- [MDN ARIA](https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAccessibility\u002FARIA)\n- [WebAIM](https:\u002F\u002Fwebaim.org\u002F)\n- [axe DevTools](https:\u002F\u002Fwww.deque.com\u002Faxe\u002Fdevtools\u002F)\n- [A11y Project](https:\u002F\u002Fwww.a11yproject.com\u002F)\n\n## Metadata\n\n### Version\n- **Current Version**: 1.0.0\n- **Last Updated**: 2025-01-01\n- **Compatible Platforms**: Claude, ChatGPT, Gemini\n\n### Related Skills\n- [ui-component-patterns](..\u002Fui-component-patterns\u002FSKILL.md): UI component implementation\n- [responsive-design](..\u002Fresponsive-design\u002FSKILL.md): Responsive design\n\n### Tags\n`#accessibility` `#a11y` `#WCAG` `#ARIA` `#screen-reader` `#keyboard-navigation` `#frontend`\n","# Web Accessibility (A11y)\n\n\n## When to use this skill\n\n- **New UI Component Development**: Designing accessible components\n- **Accessibility Audit**: Identifying and fixing accessibility issues in existing sites\n- **Form Implementation**: Writing screen reader-friendly forms\n- **Modals\u002FDropdowns**: Focus management and keyboard trap prevention\n- **WCAG Compliance**: Meeting legal requirements or standards\n\n## Input Format\n\n### Required Information\n- **Framework**: React, Vue, Svelte, Vanilla JS, etc.\n- **Component Type**: Button, Form, Modal, Dropdown, Navigation, etc.\n- **WCAG Level**: A, AA, AAA (default: AA)\n\n### Optional Information\n- **Screen Reader**: NVDA, JAWS, VoiceOver (for testing)\n- **Automated Testing Tool**: axe-core, Pa11y, Lighthouse (default: axe-core)\n- **Browser**: Chrome, Firefox, Safari (default: Chrome)\n\n### Input Example\n\n```\nMake a React modal component accessible:\n- Framework: React + TypeScript\n- WCAG Level: AA\n- Requirements:\n  - Focus trap (focus stays inside the modal)\n  - Close with ESC key\n  - Close by clicking the background\n  - Title\u002Fdescription read by screen readers\n```\n\n## Instructions\n\n### Step 1: Use Semantic HTML\n\nUse meaningful HTML elements to make the structure clear.\n\n**Tasks**:\n- Use semantic tags: `\u003Cbutton>`, `\u003Cnav>`, `\u003Cmain>`, `\u003Cheader>`, `\u003Cfooter>`, etc.\n- Avoid overusing `\u003Cdiv>` and `\u003Cspan>`\n- Use heading hierarchy (`\u003Ch1>` ~ `\u003Ch6>`) correctly\n- Connect `\u003Clabel>` with `\u003Cinput>`\n\n**Example** (❌ Bad vs ✅ Good):\n```html\n\u003C!-- ❌ Bad example: using only div and span -->\n\u003Cdiv class=\"header\">\n  \u003Cspan class=\"title\">My App\u003C\u002Fspan>\n  \u003Cdiv class=\"nav\">\n    \u003Cdiv class=\"nav-item\" onclick=\"navigate()\">Home\u003C\u002Fdiv>\n    \u003Cdiv class=\"nav-item\" onclick=\"navigate()\">About\u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\n\u003C!-- ✅ Good example: semantic HTML -->\n\u003Cheader>\n  \u003Ch1>My App\u003C\u002Fh1>\n  \u003Cnav aria-label=\"Main navigation\">\n    \u003Cul>\n      \u003Cli>\u003Ca href=\"\u002F\">Home\u003C\u002Fa>\u003C\u002Fli>\n      \u003Cli>\u003Ca href=\"\u002Fabout\">About\u003C\u002Fa>\u003C\u002Fli>\n    \u003C\u002Ful>\n  \u003C\u002Fnav>\n\u003C\u002Fheader>\n```\n\n**Form Example**:\n```html\n\u003C!-- ❌ Bad example: no label -->\n\u003Cinput type=\"text\" placeholder=\"Enter your name\">\n\n\u003C!-- ✅ Good example: label connected -->\n\u003Clabel for=\"name\">Name:\u003C\u002Flabel>\n\u003Cinput type=\"text\" id=\"name\" name=\"name\" required>\n\n\u003C!-- Or wrap with label -->\n\u003Clabel>\n  Email:\n  \u003Cinput type=\"email\" name=\"email\" required>\n\u003C\u002Flabel>\n```\n\n### Step 2: Implement Keyboard Navigation\n\nEnsure all features are usable without a mouse.\n\n**Tasks**:\n- Move focus with Tab and Shift+Tab\n- Activate buttons with Enter\u002FSpace\n- Navigate lists\u002Fmenus with arrow keys\n- Close modals\u002Fdropdowns with ESC\n- Use `tabindex` appropriately\n\n**Decision Criteria**:\n- Interactive elements → `tabindex=\"0\"` (focusable)\n- Exclude from focus order → `tabindex=\"-1\"` (programmatic focus only)\n- Do not change focus order → avoid using `tabindex=\"1+\"`\n\n**Example** (React Dropdown):\n```typescript\nimport React, { useState, useRef, useEffect } from 'react';\n\ninterface DropdownProps {\n  label: string;\n  options: { value: string; label: string }[];\n  onChange: (value: string) => void;\n}\n\nfunction AccessibleDropdown({ label, options, onChange }: DropdownProps) {\n  const [isOpen, setIsOpen] = useState(false);\n  const [selectedIndex, setSelectedIndex] = useState(0);\n  const buttonRef = useRef\u003CHTMLButtonElement>(null);\n  const listRef = useRef\u003CHTMLUListElement>(null);\n\n  \u002F\u002F Keyboard handler\n  const handleKeyDown = (e: React.KeyboardEvent) => {\n    switch (e.key) {\n      case 'ArrowDown':\n        e.preventDefault();\n        if (!isOpen) {\n          setIsOpen(true);\n        } else {\n          setSelectedIndex((prev) => (prev + 1) % options.length);\n        }\n        break;\n\n      case 'ArrowUp':\n        e.preventDefault();\n        if (!isOpen) {\n          setIsOpen(true);\n        } else {\n          setSelectedIndex((prev) => (prev - 1 + options.length) % options.length);\n        }\n        break;\n\n      case 'Enter':\n      case ' ':\n        e.preventDefault();\n        if (isOpen) {\n          onChange(options[selectedIndex].value);\n          setIsOpen(false);\n          buttonRef.current?.focus();\n        } else {\n          setIsOpen(true);\n        }\n        break;\n\n      case 'Escape':\n        e.preventDefault();\n        setIsOpen(false);\n        buttonRef.current?.focus();\n        break;\n    }\n  };\n\n  return (\n    \u003Cdiv className=\"dropdown\">\n      \u003Cbutton\n        ref={buttonRef}\n        onClick={() => setIsOpen(!isOpen)}\n        onKeyDown={handleKeyDown}\n        aria-haspopup=\"listbox\"\n        aria-expanded={isOpen}\n        aria-labelledby=\"dropdown-label\"\n      >\n        {label}\n      \u003C\u002Fbutton>\n\n      {isOpen && (\n        \u003Cul\n          ref={listRef}\n          role=\"listbox\"\n          aria-labelledby=\"dropdown-label\"\n          onKeyDown={handleKeyDown}\n          tabIndex={-1}\n        >\n          {options.map((option, index) => (\n            \u003Cli\n              key={option.value}\n              role=\"option\"\n              aria-selected={index === selectedIndex}\n              onClick={() => {\n                onChange(option.value);\n                setIsOpen(false);\n              }}\n            >\n              {option.label}\n            \u003C\u002Fli>\n          ))}\n        \u003C\u002Ful>\n      )}\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n### Step 3: Add ARIA Attributes\n\nProvide additional context for screen readers.\n\n**Tasks**:\n- `aria-label`: Define the element's name\n- `aria-labelledby`: Reference another element as a label\n- `aria-describedby`: Provide additional description\n- `aria-live`: Announce dynamic content changes\n- `aria-hidden`: Hide from screen readers\n\n**Checklist**:\n- [x] All interactive elements have clear labels\n- [x] Button purpose is clear (e.g., \"Submit form\" not \"Click\")\n- [x] State change announcements (aria-live)\n- [x] Decorative images use alt=\"\" or aria-hidden=\"true\"\n\n**Example** (Modal):\n```tsx\nfunction AccessibleModal({ isOpen, onClose, title, children }) {\n  const modalRef = useRef\u003CHTMLDivElement>(null);\n\n  \u002F\u002F Focus trap when modal opens\n  useEffect(() => {\n    if (isOpen) {\n      modalRef.current?.focus();\n    }\n  }, [isOpen]);\n\n  if (!isOpen) return null;\n\n  return (\n    \u003Cdiv\n      role=\"dialog\"\n      aria-modal=\"true\"\n      aria-labelledby=\"modal-title\"\n      aria-describedby=\"modal-description\"\n      ref={modalRef}\n      tabIndex={-1}\n      onKeyDown={(e) => {\n        if (e.key === 'Escape') {\n          onClose();\n        }\n      }}\n    >\n      \u003Cdiv className=\"modal-overlay\" onClick={onClose} aria-hidden=\"true\" \u002F>\n\n      \u003Cdiv className=\"modal-content\">\n        \u003Ch2 id=\"modal-title\">{title}\u003C\u002Fh2>\n        \u003Cdiv id=\"modal-description\">\n          {children}\n        \u003C\u002Fdiv>\n\n        \u003Cbutton onClick={onClose} aria-label=\"Close modal\">\n          \u003Cspan aria-hidden=\"true\">×\u003C\u002Fspan>\n        \u003C\u002Fbutton>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n**aria-live Example** (Notifications):\n```tsx\nfunction Notification({ message, type }: { message: string; type: 'success' | 'error' }) {\n  return (\n    \u003Cdiv\n      role=\"alert\"\n      aria-live=\"assertive\"  \u002F\u002F Immediate announcement (error), \"polite\" announces in turn\n      aria-atomic=\"true\"     \u002F\u002F Read the entire content\n      className={`notification notification-${type}`}\n    >\n      {type === 'error' && \u003Cspan aria-label=\"Error\">⚠️\u003C\u002Fspan>}\n      {type === 'success' && \u003Cspan aria-label=\"Success\">✅\u003C\u002Fspan>}\n      {message}\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n### Step 4: Color Contrast and Visual Accessibility\n\nEnsure sufficient contrast ratios for users with visual impairments.\n\n**Tasks**:\n- WCAG AA: text 4.5:1, large text 3:1\n- WCAG AAA: text 7:1, large text 4.5:1\n- Do not convey information by color alone (use icons, patterns alongside)\n- Clearly indicate focus (outline)\n\n**Example** (CSS):\n```css\n\u002F* ✅ Sufficient contrast (text #000 on #FFF = 21:1) *\u002F\n.button {\n  background-color: #0066cc;\n  color: #ffffff;  \u002F* contrast ratio 7.7:1 *\u002F\n}\n\n\u002F* ✅ Focus indicator *\u002F\nbutton:focus,\na:focus {\n  outline: 3px solid #0066cc;\n  outline-offset: 2px;\n}\n\n\u002F* ❌ outline: none is forbidden! *\u002F\nbutton:focus {\n  outline: none;  \u002F* Never use this *\u002F\n}\n\n\u002F* ✅ Indicate state with color + icon *\u002F\n.error-message {\n  color: #d32f2f;\n  border-left: 4px solid #d32f2f;\n}\n\n.error-message::before {\n  content: '⚠️';\n  margin-right: 8px;\n}\n```\n\n### Step 5: Accessibility Testing\n\nValidate accessibility with automated and manual testing.\n\n**Tasks**:\n- Automated scan with axe DevTools\n- Check Lighthouse Accessibility score\n- Test all features with keyboard only\n- Screen reader testing (NVDA, VoiceOver)\n\n**Example** (Jest + axe-core):\n```typescript\nimport { render } from '@testing-library\u002Freact';\nimport { axe, toHaveNoViolations } from 'jest-axe';\nimport AccessibleButton from '.\u002FAccessibleButton';\n\nexpect.extend(toHaveNoViolations);\n\ndescribe('AccessibleButton', () => {\n  it('should have no accessibility violations', async () => {\n    const { container } = render(\n      \u003CAccessibleButton onClick={() => {}}>\n        Click Me\n      \u003C\u002FAccessibleButton>\n    );\n\n    const results = await axe(container);\n    expect(results).toHaveNoViolations();\n  });\n\n  it('should be keyboard accessible', () => {\n    const handleClick = jest.fn();\n    const { getByRole } = render(\n      \u003CAccessibleButton onClick={handleClick}>\n        Click Me\n      \u003C\u002FAccessibleButton>\n    );\n\n    const button = getByRole('button');\n\n    \u002F\u002F Enter key\n    button.focus();\n    fireEvent.keyDown(button, { key: 'Enter' });\n    expect(handleClick).toHaveBeenCalled();\n\n    \u002F\u002F Space key\n    fireEvent.keyDown(button, { key: ' ' });\n    expect(handleClick).toHaveBeenCalledTimes(2);\n  });\n});\n```\n\n## Output format\n\n### Basic Checklist\n\n```markdown\n## Accessibility Checklist\n\n### Semantic HTML\n- [x] Use semantic HTML tags (`\u003Cbutton>`, `\u003Cnav>`, `\u003Cmain>`, etc.)\n- [x] Heading hierarchy is correct (h1 → h2 → h3)\n- [x] All form labels are connected\n\n### Keyboard Navigation\n- [x] All interactive elements accessible via Tab\n- [x] Buttons activated with Enter\u002FSpace\n- [x] Modals\u002Fdropdowns closed with ESC\n- [x] Focus indicator is clear (outline)\n\n### ARIA\n- [x] `role` used appropriately\n- [x] `aria-label` or `aria-labelledby` provided\n- [x] `aria-live` used for dynamic content\n- [x] Decorative elements use `aria-hidden=\"true\"`\n\n### Visual\n- [x] Color contrast meets WCAG AA (4.5:1)\n- [x] Information not conveyed by color alone\n- [x] Text size can be adjusted\n- [x] Responsive design\n\n### Testing\n- [x] 0 axe DevTools violations\n- [x] Lighthouse Accessibility score 90+\n- [x] Keyboard test passed\n- [x] Screen reader test completed\n```\n\n## Constraints\n\n### Mandatory Rules (MUST)\n\n1. **Keyboard Accessibility**: All features must be usable without a mouse\n   - Support Tab, Enter, Space, arrow keys, and ESC\n   - Implement focus trap (for modals)\n\n2. **Alternative Text**: All images must have an `alt` attribute\n   - Meaningful images: descriptive alt text\n   - Decorative images: `alt=\"\"` (screen reader ignores)\n\n3. **Clear Labels**: All form inputs must have an associated label\n   - `\u003Clabel for=\"...\">` or `aria-label`\n   - Do not use placeholder alone as a substitute for a label\n\n### Prohibited Actions (MUST NOT)\n\n1. **Do Not Remove Outline**: Never use `outline: none`\n   - Disastrous for keyboard users\n   - Must provide a custom focus style instead\n\n2. **Do Not Use tabindex > 0**: Avoid changing focus order\n   - Keep DOM order logical\n   - Exception: only when there is a special reason\n\n3. **Do Not Convey Information by Color Alone**: Accompany with icons or text\n   - Consider users with color blindness\n   - e.g., \"Click red item\" → \"Click ⚠️ Error item\"\n\n## Examples\n\n### Example 1: Accessible Form\n\n```tsx\nfunction AccessibleContactForm() {\n  const [errors, setErrors] = useState\u003CRecord\u003Cstring, string>>({});\n  const [submitStatus, setSubmitStatus] = useState\u003C'idle' | 'success' | 'error'>('idle');\n\n  return (\n    \u003Cform onSubmit={handleSubmit} noValidate>\n      \u003Ch2 id=\"form-title\">Contact Us\u003C\u002Fh2>\n      \u003Cp id=\"form-description\">Please fill out the form below to get in touch.\u003C\u002Fp>\n\n      {\u002F* Name *\u002F}\n      \u003Cdiv className=\"form-group\">\n        \u003Clabel htmlFor=\"name\">\n          Name \u003Cspan aria-label=\"required\">*\u003C\u002Fspan>\n        \u003C\u002Flabel>\n        \u003Cinput\n          type=\"text\"\n          id=\"name\"\n          name=\"name\"\n          required\n          aria-required=\"true\"\n          aria-invalid={!!errors.name}\n          aria-describedby={errors.name ? 'name-error' : undefined}\n        \u002F>\n        {errors.name && (\n          \u003Cspan id=\"name-error\" role=\"alert\" className=\"error\">\n            {errors.name}\n          \u003C\u002Fspan>\n        )}\n      \u003C\u002Fdiv>\n\n      {\u002F* Email *\u002F}\n      \u003Cdiv className=\"form-group\">\n        \u003Clabel htmlFor=\"email\">\n          Email \u003Cspan aria-label=\"required\">*\u003C\u002Fspan>\n        \u003C\u002Flabel>\n        \u003Cinput\n          type=\"email\"\n          id=\"email\"\n          name=\"email\"\n          required\n          aria-required=\"true\"\n          aria-invalid={!!errors.email}\n          aria-describedby={errors.email ? 'email-error' : 'email-hint'}\n        \u002F>\n        \u003Cspan id=\"email-hint\" className=\"hint\">\n          We'll never share your email.\n        \u003C\u002Fspan>\n        {errors.email && (\n          \u003Cspan id=\"email-error\" role=\"alert\" className=\"error\">\n            {errors.email}\n          \u003C\u002Fspan>\n        )}\n      \u003C\u002Fdiv>\n\n      {\u002F* Submit button *\u002F}\n      \u003Cbutton type=\"submit\" disabled={submitStatus === 'loading'}>\n        {submitStatus === 'loading' ? 'Submitting...' : 'Submit'}\n      \u003C\u002Fbutton>\n\n      {\u002F* Success\u002Ffailure messages *\u002F}\n      {submitStatus === 'success' && (\n        \u003Cdiv role=\"alert\" aria-live=\"polite\" className=\"success\">\n          ✅ Form submitted successfully!\n        \u003C\u002Fdiv>\n      )}\n\n      {submitStatus === 'error' && (\n        \u003Cdiv role=\"alert\" aria-live=\"assertive\" className=\"error\">\n          ⚠️ An error occurred. Please try again.\n        \u003C\u002Fdiv>\n      )}\n    \u003C\u002Fform>\n  );\n}\n```\n\n### Example 2: Accessible Tab UI\n\n```tsx\nfunction AccessibleTabs({ tabs }: { tabs: { id: string; label: string; content: React.ReactNode }[] }) {\n  const [activeTab, setActiveTab] = useState(0);\n\n  const handleKeyDown = (e: React.KeyboardEvent, index: number) => {\n    switch (e.key) {\n      case 'ArrowRight':\n        e.preventDefault();\n        setActiveTab((index + 1) % tabs.length);\n        break;\n      case 'ArrowLeft':\n        e.preventDefault();\n        setActiveTab((index - 1 + tabs.length) % tabs.length);\n        break;\n      case 'Home':\n        e.preventDefault();\n        setActiveTab(0);\n        break;\n      case 'End':\n        e.preventDefault();\n        setActiveTab(tabs.length - 1);\n        break;\n    }\n  };\n\n  return (\n    \u003Cdiv>\n      {\u002F* Tab List *\u002F}\n      \u003Cdiv role=\"tablist\" aria-label=\"Content sections\">\n        {tabs.map((tab, index) => (\n          \u003Cbutton\n            key={tab.id}\n            role=\"tab\"\n            id={`tab-${tab.id}`}\n            aria-selected={activeTab === index}\n            aria-controls={`panel-${tab.id}`}\n            tabIndex={activeTab === index ? 0 : -1}\n            onClick={() => setActiveTab(index)}\n            onKeyDown={(e) => handleKeyDown(e, index)}\n          >\n            {tab.label}\n          \u003C\u002Fbutton>\n        ))}\n      \u003C\u002Fdiv>\n\n      {\u002F* Tab Panels *\u002F}\n      {tabs.map((tab, index) => (\n        \u003Cdiv\n          key={tab.id}\n          role=\"tabpanel\"\n          id={`panel-${tab.id}`}\n          aria-labelledby={`tab-${tab.id}`}\n          hidden={activeTab !== index}\n          tabIndex={0}\n        >\n          {tab.content}\n        \u003C\u002Fdiv>\n      ))}\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n## Best practices\n\n1. **Semantic HTML First**: ARIA is a last resort\n   - Using the correct HTML element makes ARIA unnecessary\n   - e.g., `\u003Cbutton>` vs `\u003Cdiv role=\"button\">`\n\n2. **Focus Management**: Manage focus on page transitions in SPAs\n   - Move focus to main content on new page load\n   - Provide skip links (\"Skip to main content\")\n\n3. **Error Messages**: Clear and helpful error messages\n   - \"Invalid input\" ❌ → \"Email must be in format: example@domain.com\" ✅\n\n## References\n\n- [WCAG 2.1 Guidelines](https:\u002F\u002Fwww.w3.org\u002FWAI\u002FWCAG21\u002Fquickref\u002F)\n- [MDN ARIA](https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAccessibility\u002FARIA)\n- [WebAIM](https:\u002F\u002Fwebaim.org\u002F)\n- [axe DevTools](https:\u002F\u002Fwww.deque.com\u002Faxe\u002Fdevtools\u002F)\n- [A11y Project](https:\u002F\u002Fwww.a11yproject.com\u002F)\n\n## Metadata\n\n### Version\n- **Current Version**: 1.0.0\n- **Last Updated**: 2025-01-01\n- **Compatible Platforms**: Claude, ChatGPT, Gemini\n\n### Related Skills\n- [ui-component-patterns](..\u002Fui-component-patterns\u002FSKILL.md): UI component implementation\n- [responsive-design](..\u002Fresponsive-design\u002FSKILL.md): Responsive design\n\n### Tags\n`#accessibility` `#a11y` `#WCAG` `#ARIA` `#screen-reader` `#keyboard-navigation` `#frontend`\n",{"name":5,"metadata":52,"description":7},{"tags":53,"platforms":54},"accessibility, a11y, WCAG, ARIA, semantic-HTML, screen-reader","Claude, ChatGPT, Gemini","main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Faiskillstore\u002Fmarketplace\u002Fsupercent-io\u002Fweb-accessibility",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":65,"prompt":75,"zipAvailable":76},[66,69,72],{"tool":67,"command":68},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill web-accessibility",{"tool":70,"command":71},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill web-accessibility",{"tool":73,"command":74},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill web-accessibility","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fsupercent-io\u002Fweb-accessibility\u002FSKILL.md",true,[78,84],{"path":79,"resourceType":80,"resourceTypeDesc":81,"sizeBytes":82,"sourceHtmlUrl":83},"skill-report.json","REFERENCE","参考文档",8684,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fsupercent-io\u002Fweb-accessibility\u002Fskill-report.json",{"path":85,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":88,"sourceHtmlUrl":89},"SKILL.toon","OTHER","其他",823,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fsupercent-io\u002Fweb-accessibility\u002FSKILL.toon",[91,103,113,122,128,135],{"skillNo":92,"name":93,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":94,"categories":95,"keywords":99,"publishedAt":47},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[96],{"categoryNo":97,"categoryName":98,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[100,101,102],"model","model hierarchy","model hierarchy skill",{"skillNo":104,"name":105,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":106,"categories":107,"keywords":109,"publishedAt":47},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[108],{"categoryNo":97,"categoryName":98,"taxonomyType":21,"taxonomyTypeDesc":22},[110,111,112],"MCP","zoom","zoom mcp",{"skillNo":114,"name":115,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":116,"categories":117,"keywords":118,"publishedAt":47},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[119,120,121,111],"sdk","zoom apps sdk","apps",{"skillNo":123,"name":124,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":125,"categories":126,"keywords":127,"publishedAt":47},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[124],{"skillNo":129,"name":130,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":131,"categories":132,"keywords":134,"publishedAt":47},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[133],{"categoryNo":97,"categoryName":98,"taxonomyType":21,"taxonomyTypeDesc":22},[130],{"skillNo":136,"name":137,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":138,"categories":139,"keywords":140,"publishedAt":47},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[137]]