Best for
- Use when reviewing React components, hooks, props, state, styling, and accessibility.
agents-inc/skills/src/skills/meta-reviewing-web-reviewing/SKILL.md
UI component review patterns. Use when reviewing React components, hooks, props, state, styling, and accessibility. Covers rules of hooks, effect cleanup, render performance, list keys, keyboard and ARIA patterns.
Decision brief
Quick Guide: When a diff touches UI components, verify hooks obey the rules of hooks with complete dependency arrays, effects clean up what they set up, list keys are stable, and interactive elements the diff adds are reachable by keyboard with accessible names. Judge performanc…
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/agents-inc/skills --skill "src/skills/meta-reviewing-web-reviewing"Inspect the Agent Skill "meta-reviewing-web-reviewing" from https://github.com/agents-inc/skills/blob/81d43a51211aca12c85dcc16085fa99014ec548e/src/skills/meta-reviewing-web-reviewing/SKILL.md at commit 81d43a51211aca12c85dcc16085fa99014ec548e. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
For EACH hook call in the diff:
For EACH effect the diff adds or changes:
// Good: derive it const name = user.name; markdown
Flag ONLY with evidence in the diff:
[ ] value is always paired with onChange (or the input is deliberately uncontrolled via defaultValue)
Permission review
No configured static risk pattern was detected
This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.
Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 91/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 23 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Quick Guide: When a diff touches UI components, verify hooks obey the rules of hooks with complete dependency arrays, effects clean up what they set up, list keys are stable, and interactive elements the diff adds are reachable by keyboard with accessible names. Judge performance concerns against evidence in the diff, not against a memoize-everything ideal.
<critical_requirements>
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST verify hooks are called unconditionally at top level, with dependency arrays that name every value the callback reads)
(You MUST verify every effect that subscribes, registers a listener, or starts a timer returns a cleanup function)
(You MUST check every interactive element the diff adds for keyboard reachability and an accessible name)
(You MUST verify list keys are stable identities, not array indexes on lists that can reorder)
(You MUST check memoization against evidence: flag a missing memo only for a demonstrable cost in the diff, and flag speculative memo/useCallback wrapping as churn)
</critical_requirements>
Auto-detection: review component, React PR review, hooks review, JSX diff, component code review, accessibility review, a11y check, re-render review
When to use:
.tsx/.jsx with JSX)When NOT to use:
Key patterns covered:
Detailed Resources:
Review the component the diff builds, not the component you would have built. React offers many valid shapes for the same UI; flag deviations from the codebase's established patterns and genuine defects, not alternatives.
When reviewing web code:
When NOT to flag:
React.memo, useMemo, or useCallback without a demonstrable cost in the diff - speculative memoization is churn that obscures the data flowCore principles:
Hooks must be unconditional and their dependency arrays complete.
## Hooks Review
For EACH hook call in the diff:
- [ ] Called at top level - not inside conditionals, loops, or early-return paths
- [ ] Dependency array names every prop, state value, and function the callback reads
- [ ] No dependency silenced with an eslint-disable that lacks a justifying comment
- [ ] Functions used as dependencies are stable (defined outside, or wrapped where identity matters)
// Must Fix: stale closure - `filter` is read but not declared
useEffect(() => {
fetchItems(filter).then(setItems);
}, []); // runs once, forever using the first render's filter
// Good: complete dependencies
useEffect(() => {
fetchItems(filter).then(setItems);
}, [filter]);
Why this matters: An incomplete dependency array pins the callback to stale values. The bug is invisible until the value changes, then the UI silently shows old data.
What an effect starts, its cleanup must stop.
## Effect Cleanup Review
For EACH effect the diff adds or changes:
- [ ] Subscriptions are unsubscribed in the returned cleanup
- [ ] Event listeners added to window/document are removed
- [ ] Timers (setTimeout/setInterval) are cleared
- [ ] In-flight async work is guarded (AbortController or a cancelled flag) before setState
// Must Fix: listener leaks on every unmount/remount
useEffect(() => {
window.addEventListener("resize", onResize);
}, [onResize]);
// Good: symmetric cleanup
useEffect(() => {
window.addEventListener("resize", onResize);
return () => window.removeEventListener("resize", onResize);
}, [onResize]);
Why this matters: Missing cleanup leaks listeners and timers, and setState after unmount throws warnings and hides real errors under noise.
Types should describe the component's real contract.
## Props and State Review
- [ ] Props interface/type is explicit - no `any`, no over-wide `object`/`Function`
- [ ] Optional props are genuinely optional (component behaves without them)
- [ ] State is minimal: values derivable from props/state are computed, not stored
- [ ] Derived state is not mirrored with an effect that copies props into state
// Should Fix: mirrored state drifts from its source
const [name, setName] = useState(user.name);
useEffect(() => setName(user.name), [user.name]);
// Good: derive it
const name = user.name;
Why this matters: Every duplicated source of truth is a future inconsistency; effects that sync state are the classic source of render loops.
Performance feedback must point at a cost the diff creates.
## Performance Review
Flag ONLY with evidence in the diff:
- [ ] A genuinely expensive computation (large sort/filter/parse) running on every render → suggest useMemo
- [ ] A new object/array/function literal passed to a memoized child, defeating its memo → stabilize it
- [ ] State lifted so high that broad subtrees re-render on every keystroke → suggest lowering it
Do NOT flag:
- Plain components without React.memo - that is the default, not a defect
- Inline handlers passed to plain DOM elements or non-memoized children
- useMemo around cheap expressions
// Don't Mention: cheap derivation, memo would be noise
const label = `${first} ${last}`;
// Should Fix: expensive work re-runs on every keystroke of an unrelated input
const ranked = rankResults(allResults); // 10k items, in render body
// → const ranked = useMemo(() => rankResults(allResults), [allResults]);
Why this matters: Blanket memoization advice rewards volume over insight and adds indirection with no measured benefit. The review should catch real costs and equally catch speculative wrapping.
Keys are identities, not positions.
// Must Fix: index keys on a reorderable/filterable list
{items.map((item, i) => <Row key={i} item={item} />)}
// Good: stable identity
{items.map((item) => <Row key={item.id} item={item} />)}
Why this matters: Index keys make React reuse component state across different items when the list reorders - checkboxes stay checked on the wrong row.
An input is controlled or uncontrolled - not both.
## Controlled Input Review
- [ ] `value` is always paired with `onChange` (or the input is deliberately uncontrolled via defaultValue)
- [ ] The value passed is never undefined-then-defined across renders (controlled/uncontrolled flip)
- [ ] Handlers receive typed events, not `any`
- [ ] Form submission prevents default before async work
Why this matters: A controlled/uncontrolled flip throws warnings and drops user input; untyped handlers hide event misuse.
Everything interactive the diff adds must be operable without a mouse.
## Accessibility Review (diff-added elements only)
- [ ] Semantic elements used: button for actions, a for navigation - not onClick on div/span
- [ ] Every form input has an associated label (htmlFor/id, wrapping label, or aria-label)
- [ ] Icon-only buttons carry an accessible name (aria-label)
- [ ] Custom interactive widgets are keyboard-operable and show focus
- [ ] Focus is managed where the diff moves it: dialogs trap and restore focus on close
- [ ] ARIA attributes added are valid and necessary - semantic HTML needs no aria-role restating
// Must Fix: unreachable by keyboard, no accessible name
<div onClick={openSettings}><GearIcon /></div>
// Good: semantic, named, focusable for free
<button type="button" aria-label="Open settings" onClick={openSettings}>
<GearIcon />
</button>
Why this matters: A div with onClick is invisible to keyboard and screen-reader users. Semantic elements deliver focus, activation, and naming for free - the review's job is to catch the places the diff opted out.
<decision_framework>
Is this a correctness or accessibility defect the diff introduces?
├─ Incomplete dependency array reading changing values → MUST FIX
├─ Effect without cleanup for listener/timer/subscription → MUST FIX
├─ Conditional hook call → MUST FIX
├─ Index keys on a reorderable list → MUST FIX
├─ Diff-added interactive element unreachable by keyboard or unnamed → MUST FIX
└─ NO → Does it degrade maintainability or real performance?
├─ Demonstrably expensive computation in render body → SHOULD FIX
├─ Fresh literal defeating an existing memoized child → SHOULD FIX
├─ Props mirrored into state with a sync effect → SHOULD FIX
├─ Untyped props or `any` in handlers → SHOULD FIX
└─ NO → Is it a genuine enhancement?
├─ Extracting a reusable hook two components now duplicate → NICE TO HAVE
├─ React.memo without a measured re-render cost → DON'T MENTION
├─ Component decomposition preference → DON'T MENTION
└─ Styling taste within the file's existing approach → DON'T MENTION
</decision_framework>
<red_flags>
High Priority Issues (Must Fix):
useEffect/useMemo/useCallback with an empty or incomplete dependency array reading values that changekey={index} on a list that can reorder, filter, or insertonClick on non-interactive elements with no keyboard pathMedium Priority Issues (Should Fix):
React.memo childany-typed props, events, or refsCommon Mistakes:
useCallback as free - it costs a dependency array to maintainGotchas & Edge Cases:
aria-* attributes on the wrong element are worse than none - verify against the pattern, don't just count them</red_flags>
<critical_reminders>
All code must follow project conventions in CLAUDE.md
(You MUST verify hooks are called unconditionally at top level, with dependency arrays that name every value the callback reads)
(You MUST verify every effect that subscribes, registers a listener, or starts a timer returns a cleanup function)
(You MUST check every interactive element the diff adds for keyboard reachability and an accessible name)
(You MUST verify list keys are stable identities, not array indexes on lists that can reorder)
(You MUST check memoization against evidence: flag a missing memo only for a demonstrable cost in the diff, and flag speculative memo/useCallback wrapping as churn)
Failure to catch these issues will result in components that leak listeners, render stale data, lose user input on reorder, and lock out keyboard users.
</critical_reminders>
Frequently asked questions
Quick Guide: When a diff touches UI components, verify hooks obey the rules of hooks with complete dependency arrays, effects clean up what they set up, list keys are stable, and interactive elements the diff adds are reachable by keyboard with accessible names. Judge performanc…
The source record exposes this install command: npx skills add https://github.com/agents-inc/skills --skill "src/skills/meta-reviewing-web-reviewing". Inspect the command and pinned source before running it.
Alternatives
magnus919/agent-skills
Use this skill to reverse-engineer an existing software system, map its architecture, data flow, privacy posture, coupling, quality characteristics, and feature surface, then produce an evidence-grounded clean-room design document, PRD, or migration plan under new constraints. Use for codebase archaeology, implicit contract extraction, architecture health assessment, or decomposition-readiness analysis. Do not use for greenfield architecture design, direct code review, bug hunting, security audi
Jamie-BitFlight/claude_skills
Use when building Python 3.11+ CLI apps (Typer/Rich), writing pytest test suites, fixing ruff linting or ty/mypy type errors, configuring pyproject.toml, creating portable scripts, or reviewing Python code. Activates on all Python implementation tasks — routes to specialist agents for CLI architecture, test design, packaging, and code review. Authoritative reference for modern Python 3.11-3.14 patterns and TDD workflows.
Jamie-BitFlight/claude_skills
Shared Python 3.11+ development standards covering type safety (ty, native generics, Protocol, TypeIs), layered architecture, error handling, performance, identifier naming, UI/CLI patterns (Rich/Typer), testing requirements (pytest, 80% coverage, TDD), and quality gates. Activates when any Python skill or agent needs to apply shared standards for implementation, code review, refactoring, or test authoring.
kirodotdev/KiroCrew
Deep, platform-neutral code review for PRs and CRs in ONE thorough single pass — design reasoning (Problem Worth Solving & Solution Fit) as one dimension alongside the 9 code-level dimensions, with chain-of-consequences, self-critique, and draft-only comments. The single app-owned source of truth.