{"manifest":{"name":"React Component Reviewer","version":"1.0.0","description":"Deep review of React/TSX components against a 12-point checklist: hook violations, missing keys, ARIA attributes, memoization, prop drilling, missing dependencies, and more.","tags":["react","typescript","code-review","accessibility","hooks"],"standard":"agentskills.io","standard_version":"1.0","content_checksum":"911aae45537e0f739f68c574eb32f30a3318290c448dd2e1200ea0e83a83c0ee","bundle_checksum":null,"metadata":{},"files":[]},"files":{"SKILL.md":"# React Component Reviewer\n\n> **Purpose:** Perform a deep, systematic review of a React TypeScript component (.tsx) against a specific 12-point checklist. Goes beyond generic code review to catch React-specific anti-patterns that general reviewers miss. Produces annotated findings with exact fix suggestions.\n\n---\n\n## Invocation\n\n```\n/react-review <file.tsx>\n```\n\n---\n\n## The 12-Point Checklist\n\n### 1. Hook Order Violations\n- Are hooks called conditionally or inside loops? (breaks Rules of Hooks)\n- Are hooks called in the same order on every render?\n\n### 2. Missing `key` Props in Lists\n- Every `.map()` that returns JSX must have a stable `key` prop\n- `key` must not be the array index when the list can reorder or filter\n\n### 3. Missing or Incorrect ARIA Attributes\n- Interactive elements (`<div onClick>`, `<span onClick>`) must have `role` and keyboard handlers\n- Images must have `alt` attribute (empty string `alt=\"\"` for decorative images)\n- Form inputs must have associated `<label>` via `htmlFor` or `aria-label`\n- Modal/dialog elements must have `aria-modal`, `role=\"dialog\"`, and focus trap\n\n### 4. Missing `React.memo` on Pure Components\n- Components that receive complex objects as props and re-render frequently\n- Components that are used inside lists and receive non-primitive props\n- Note: `memo` is not needed everywhere — flag only genuine candidates\n\n### 5. Prop Drilling Deeper Than 2 Levels\n- Props passed through 3+ component layers without being used in intermediate components\n- Suggest: React Context, component composition, or lifting state differently\n\n### 6. `useEffect` Missing Dependencies or Stale Closures\n- Variables used inside `useEffect` but not in the dependency array\n- Functions defined outside `useEffect` used inside without being in deps\n- Missing `useCallback` on functions passed as deps\n\n### 7. Unhandled Loading and Error States\n- Data-fetching components must render loading state (skeleton, spinner, or message)\n- Data-fetching components must render error state with actionable message\n- Empty state when data is `[]` or `null` should be handled\n\n### 8. Hardcoded Strings That Should Be Constants\n- URLs, error messages, magic numbers used directly in JSX\n- Strings used in multiple places without being defined as constants\n\n### 9. `any` Type Usage\n- Every `any` annotation in the component is a type safety hole\n- Suggest `unknown` with type narrowing, or proper interface definition\n\n### 10. Missing Null Checks on Optional Props\n- Optional chaining (`?.`) used but result not checked before rendering\n- Props that could be `undefined` rendered without a fallback\n\n### 11. Direct DOM Mutation\n- `document.getElementById()` or `document.querySelector()` inside a component\n- Suggest `useRef()` for DOM access\n\n### 12. Missing `Suspense` Boundary for Async Components\n- Components using `use()`, `React.lazy()`, or async Server Components\n- Must be wrapped in `<Suspense fallback={...}>` at the appropriate level\n\n---\n\n## Output Format\n\nFor each finding:\n\n```\n[SEVERITY] Checklist Item #N — file.tsx:line\nIssue: [what's wrong]\nFix: [exact code change or pattern to use]\n```\n\n**Severity:**\n- `CRITICAL` — Will cause runtime errors or accessibility failures\n- `HIGH` — Causes incorrect behavior or major UX issues\n- `MEDIUM` — Performance or maintainability concern\n- `LOW` — Style or minor improvement\n\nEnd with:\n\n```\n## Component Review Summary\nChecklist items reviewed: 12/12\nIssues found: [N] (Critical: N, High: N, Medium: N, Low: N)\nVerdict: APPROVE / REQUEST CHANGES / NEEDS MAJOR REWORK\n```\n\n---\n\n## Rules\n\n- All 12 checklist items must be evaluated — \"No issues\" is a valid finding for each\n- Don't flag `React.memo` absence unless there's genuine evidence of unnecessary re-renders\n- `key={index}` in a static, non-reorderable list is acceptable — flag only if the list can change\n- ARIA issues are always `HIGH` or `CRITICAL` — accessibility is not optional\n\n## Playground\n\n<!DOCTYPE html><html><head><meta charset='utf-8'><style>*{box-sizing:border-box;margin:0;padding:0}body{background:#0d1117;color:#e6edf3;font-family:monospace;font-size:12px;height:100vh;display:flex;flex-direction:column;overflow:hidden}.header{background:#161b22;border-bottom:1px solid #30363d;padding:8px 14px;font-size:11px;color:#8b949e;display:flex;justify-content:space-between;align-items:center;flex-shrink:0}.title{color:#58a6ff;font-weight:bold;font-size:13px}.panels{display:flex;flex:1;overflow:hidden}.panel{flex:1;overflow:auto;padding:12px;border-right:1px solid #30363d}.panel:last-child{border-right:none}.label{font-size:10px;color:#8b949e;text-transform:uppercase;letter-spacing:.08em;margin-bottom:6px}pre{white-space:pre-wrap;word-break:break-word;line-height:1.5}</style></head><body><div class='header'><span class='title'>React Component Reviewer</span><span>Example · SkillSlap</span></div><div class='panels'><div class='panel'><div class='label'>Input: React component</div><pre><span style='color:#8b949e'>function UserList() {</span>\n<span style='color:#8b949e'>  const [users, setUsers] = useState([])</span>\n<span style='color:#8b949e'>  useEffect(() =&gt; {</span>\n<span style='color:#8b949e'>    fetch('/api/users')</span>\n<span style='color:#8b949e'>      .then(r =&gt; r.json())</span>\n<span style='color:#8b949e'>      .then(setUsers)</span>\n<span style='color:#8b949e'>  }, [users])</span>\n<span style='color:#8b949e'>  return users.map(u =&gt;</span>\n<span style='color:#8b949e'>    &lt;div&gt;{u.name}&lt;/div&gt;</span>\n<span style='color:#8b949e'>  )</span>\n<span style='color:#8b949e'>}</span></pre></div><div class='panel'><div class='label'>Output: Review</div><pre><span style='color:#f85149'>🔴 Infinite loop (line 5)</span>\n<span style='color:#8b949e'>`users` in dep array triggers effect</span>\n<span style='color:#8b949e'>on every state update → infinite fetch.</span>\n<span style='color:#8b949e'>Fix: dep array should be `[]`</span>\n\n<span style='color:#f85149'>🔴 Missing key prop (line 8)</span>\n<span style='color:#8b949e'>React requires unique key on list items.</span>\n<span style='color:#8b949e'>Fix: &lt;div key={u.id}&gt;</span>\n\n<span style='color:#e3b341'>🟡 No loading/error state</span>\n<span style='color:#8b949e'>Blank screen while fetching, silent</span>\n<span style='color:#8b949e'>fail on error. Add isLoading + error.</span>\n\n<span style='color:#e3b341'>🟡 No AbortController</span>\n<span style='color:#8b949e'>Fetch leaks if component unmounts.</span></pre></div></div></body></html>"}}