react-standards
Skill1 starsChanged 5 months agoMITView on GitHub
Best-practice coding standards for React UI code (manifest: package.json with react). Referenced by the review agents. Covers component design, hooks, state management, rendering/performance, error boundaries, client logging, forms, testing, accessibility. Pairs with typescript-standards; Next.js apps ALSO load nextjs-standards. Do NOT use for backend or non-React frontend code.
2 other projects use a version of this.
Adopted by
Most recently taken up by
- jDxve/avengers-kittheir own version, first seen Nov 8, 2026
- humanmade/claude-code-standardstheir own version, first seen Sep 21, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- humanmade/claude-code-standards★ 6same name
- jDxve/avengers-kit★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository19 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- custom-standardsSkill
- agent-code-to-confirmSkill
- agent-to-confirmSkill
- claude-guideline-creationSkill
- skill-creatorSkill
- youtube-to-guidelineSkill
- youtube-transcribeSkill
- fastapi-standardsSkill
- general-standardsSkill
- go-standardsSkill
- java-standardsSkill
- nextjs-standardsSkill
- nodejs-standardsSkill
- python-standardsSkill
- reviewing-codebasesSkill
- rust-standardsSkill
- skill-toggleSkill
- typescript-standardsSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
27 rules. About 0 are common, 10 are distinctive, and 17 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈10
Distinctive · estimate
This author's own choices. Worth a look.
17
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 49
Target: all React source — components, hooks, context, pages.
- Very specific: line 51
Extended by
nextjs.md: when Next.js is the host — Next.js rules override or extend these where they conflict. - Very specific: line 59
REACT-COMP-1 (MUST): Write function components.
- Distinctive: line 67
REACT-COMP-3 (SHOULD): Keep components small and focused — a single visual or behavioral concern.
- Distinctive: line 70
REACT-COMP-4 (SHOULD): Prefer named exports for components.
- Distinctive: line 96
REACT-HOOK-1 (MUST): Follow the Rules of Hooks exactly:
- Distinctive: line 97
Call hooks only at the top level of a component or custom hook — never inside loops, conditions, or nested functions.
- Distinctive: line 99
Call hooks only from React function components or custom hooks.
- Very specific: line 104
REACT-HOOK-4 (SHOULD): Keep useEffect dependency arrays accurate and complete.
- Very specific: line 107
REACT-HOOK-5 (SHOULD NOT): Use useEffect to synchronize unrelated concerns in one effect block.
- Very specific: line 130
REACT-STATE-1 (MUST): MUST NOT mutate state directly.
- Very specific: line 132
REACT-STATE-2 (SHOULD): Use useState for simple, isolated local state.
- Distinctive: line 135
REACT-STATE-3 (SHOULD): Use React Context for shared state that is stable and infrequently updated (themes, locale, current user).
- Distinctive: line 150
REACT-STATE-5 (SHOULD): Keep state at the lowest common ancestor that needs it, then lift only when multiple siblings require it.
- Very specific: line 158
REACT-PERF-1 (MUST): Every list item rendered with .map() MUST have a stable, unique key prop — not an array index unless the list is …
- Very specific: line 163
REACT-PERF-3 (SHOULD): Use React.lazy + Suspense for code-splitting large components or routes.
- Very specific: line 185
REACT-ERR-1 (MUST): Every page or major feature subtree MUST be wrapped in an Error Boundary to prevent an uncaught render error from …
- Distinctive: line 189
Do not render nothing or re-throw silently.
- Very specific: line 198
REACT-SEC-1 (MUST NOT): Use dangerouslySetInnerHTML with untrusted, user-supplied content.
- Very specific: line 199
If you must inject HTML (e.g.
- Distinctive: line 209
REACT-TEST-1 (MUST): Test with React Testing Library (RTL) — test components through their rendered DOM and user interactions, not internal …
- Very specific: line 215
REACT-TEST-3 (SHOULD): Prefer userEvent over fireEvent for simulating user interactions — it triggers the full browser event sequence …
- Very specific: line 218
REACT-TEST-4 (SHOULD): Use screen queries (screen.getByRole, screen.getByLabelText) over container-based queries.
- Very specific: line 242
REACT-A11Y-1 (SHOULD): Use semantic HTML elements (<button>, <nav>, <main>, <section>) rather than generic <div>/<span> with ARIA roles …
- Very specific: line 244
REACT-A11Y-2 (SHOULD): Every interactive element MUST be reachable and activatable via keyboard.
- Very specific: line 247
REACT-A11Y-3 (SHOULD): All images MUST have an alt prop.
- Very specific: line 257
REACT-LOG-1 (MUST NOT): Leave debugging console.log/console.debug calls in committed or production client code (frontend mirror of …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
React.js Coding Standard (v1.0)
Status: Locked v1.0. Covers React as a UI library, not a full framework. This standard always pairs with
typescript.md(language rules) and is extended bynextjs.mdwhen Next.js is the host framework. Those documents own their respective concerns; this document owns component design, hooks usage, state management, rendering, forms, and testing patterns.On adoption this becomes
.claude/skills/reactjs-standards/SKILL.md+references/*.md.
Toolchain verified current as of 2026-06-13 (via Context7 + npm): React 19.2.x, @testing-library/react 16.x, Vitest 4.x,
@vitejs/plugin-react 6.x, Zustand 5.x, TanStack Query 5.x, React Hook Form 7.x +@hookform/resolvers 5.x, Zod 4.x. Rules are written version-agnostically; these are reference points, not pins.
How to read this document
Constraint language (RFC 2119)
- MUST / MUST NOT — hard requirement; a violation is a blocking issue.
- SHOULD / SHOULD NOT — strong recommendation; deviate only with a written
// Justification:. - MAY — optional.
Rule IDs
Stable REACT-AREA-NUMBER (e.g. REACT-COMP-3). The reviewer MUST cite the rule ID. Never renumber.
Severity mapping
| This document says… | Reviewer severity | Gate |
MUST/MUST NOT affecting correctness / security | Critical | Blocks merge |
MUST/MUST NOT elsewhere | Critical / Warning (by impact) | Blocks if it risks correctness |
SHOULD without justification | Warning | Should fix |
MAY / stylistic | Suggestion | Nice to have |
Scope & Assumptions
- Target: all React source — components, hooks, context, pages.
- Pairs with
typescript.md— all TypeScript rules apply; on overlap, the stricter rule wins. - Extended by
nextjs.mdwhen Next.js is the host — Next.js rules override or extend these where they conflict. - Function components only — class components are permitted only to implement Error Boundaries (no class-component API exists for them yet).
- Custom overrides: the project's
custom-standardsskill overrides this document on conflict.
1. Component Design
- REACT-COMP-1 (MUST): Write function components. Class components MUST NOT be used in new code
except as Error Boundaries (where
static getDerivedStateFromError+componentDidCatchstill require a class). - REACT-COMP-2 (MUST): Each component MUST have an explicit TypeScript props type — an
interfaceor inline object type. AvoidReact.FC<Props>: it adds no meaningful value over a plain typed function and forces an opaqueReactElement | nullreturn type instead of the inferred one. Annotate the return type (JSX.Element,React.ReactNode) only when the inferred type is not obvious to a reader. - REACT-COMP-3 (SHOULD): Keep components small and focused — a single visual or behavioral concern. Extract sub-components or custom hooks when a component grows beyond ~100 lines or has mixed unrelated concerns.
- REACT-COMP-4 (SHOULD): Prefer named exports for components. Default exports make refactoring and consistent import names harder across a large codebase.
- REACT-COMP-5 (SHOULD): Co-locate a component's types, helpers, and styles in the same
directory. Barrel
index.tsfiles are fine for public API surfaces; avoid deep re-export chains.
// ✅ REACT-COMP-2: explicit props interface, no React.FC
interface ButtonProps {
label: string;
onClick: () => void;
disabled?: boolean;
}
export function Button({ label, onClick, disabled = false }: ButtonProps) {
return (
<button onClick={onClick} disabled={disabled}>
{label}
</button>
);
}2. Hooks
- REACT-HOOK-1 (MUST): Follow the Rules of Hooks exactly:
- Call hooks only at the top level of a component or custom hook — never inside loops, conditions, or nested functions.
- Call hooks only from React function components or custom hooks.
- REACT-HOOK-2 (MUST): Name custom hooks with the
useprefix (e.g.useAuth,useCart) so linters can enforce the Rules of Hooks on them. - REACT-HOOK-3 (SHOULD): Declare
useEffectcleanup functions when the effect subscribes to anything external (timers, event listeners, subscriptions). A missing cleanup is a memory leak. - REACT-HOOK-4 (SHOULD): Keep
useEffectdependency arrays accurate and complete. Enable thereact-hooks/exhaustive-depsESLint rule. Suppressing it with// eslint-disablerequires a written justification — it usually signals a design smell. - REACT-HOOK-5 (SHOULD NOT): Use
useEffectto synchronize unrelated concerns in one effect block. Separate effects by concern; each effect should do one thing. - REACT-HOOK-6 (SHOULD NOT): Reach for
useMemo/useCallbackprematurely. Add them only when a profiler confirms a concrete rendering bottleneck — unnecessary memoization adds overhead and obscures code.
// ✅ REACT-HOOK-3: cleanup prevents memory leak
function useWindowWidth(): number {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handler = () => setWidth(window.innerWidth);
window.addEventListener('resize', handler);
return () => window.removeEventListener('resize', handler); // cleanup
}, []);
return width;
}3. State Management
- REACT-STATE-1 (MUST): MUST NOT mutate state directly. Always produce a new value —
spread objects,
map/filterarrays; neverpush/splicein place. - REACT-STATE-2 (SHOULD): Use
useStatefor simple, isolated local state. PreferuseReducerwhen state transitions are complex, have multiple sub-fields, or involve "previous state" logic — reducers are easier to test and reason about. - REACT-STATE-3 (SHOULD): Use React Context for shared state that is stable and infrequently updated (themes, locale, current user). SHOULD NOT use Context as a general-purpose store for high-frequency state updates — it re-renders every consumer on every change.
- REACT-STATE-4 (SHOULD): For non-trivial client-side global state (carts, auth, UI panels),
prefer Zustand (minimal API, no provider wrapping, no boilerplate) over a hand-rolled
context-based store. Jotai is an acceptable alternative where an atomic model fits better.
Redux Toolkit is reserved for large/legacy apps that already use it — don't reach for it in new
projects. Don't introduce a state library at all for small apps that
useState/useReducer+ Context already serve. - REACT-STATE-6 (SHOULD): Manage server/async state (data fetched from an API) with
TanStack Query — it owns fetching, caching, deduping, and refetching. You MUST NOT
re-implement this with
useEffect+fetch+useState, which leaks loading/error handling and cache logic into every component.- Next.js override: under the App Router, prefer Server Components +
fetchfor server-rendered data (seenextjs.md); TanStack Query applies to client-fetched data only.
- Next.js override: under the App Router, prefer Server Components +
- REACT-STATE-5 (SHOULD): Keep state at the lowest common ancestor that needs it, then lift only when multiple siblings require it. Avoid prop-drilling more than two levels — refactor to context or a state library at that point.
4. Rendering & Performance
- REACT-PERF-1 (MUST): Every list item rendered with
.map()MUST have a stable, uniquekeyprop — not an array index unless the list is purely static and will never reorder or change. - REACT-PERF-2 (SHOULD): Wrap expensive subtrees in
React.memoonly when profiling shows a measurable regression. Memoize prop references passed to those components withuseMemo/useCallbackso the memo comparison works. - REACT-PERF-3 (SHOULD): Use
React.lazy+Suspensefor code-splitting large components or routes. Wrap each lazy boundary in<Suspense fallback={…}>. - REACT-PERF-4 (SHOULD): Wrap user-initiated state updates that trigger expensive re-renders in
startTransitionto mark them as non-urgent, keeping the UI responsive.
// ✅ REACT-PERF-3
const HeavyChart = React.lazy(() => import('./HeavyChart'));
function Dashboard() {
return (
<Suspense fallback={<Spinner />}>
<HeavyChart />
</Suspense>
);
}5. Error Handling
- REACT-ERR-1 (MUST): Every page or major feature subtree MUST be wrapped in an Error Boundary
to prevent an uncaught render error from crashing the entire app. The boundary MUST log the error
(e.g. to an error-tracking service) in
componentDidCatch. - REACT-ERR-2 (SHOULD): Display a user-friendly fallback UI in the Error Boundary
rendermethod. Do not render nothing or re-throw silently. - REACT-ERR-3 (SHOULD): For async data fetching errors (e.g. failed API calls), handle them in
TanStack Query's
errorstate or the component's error branch — do not let them surface as unhandled promise rejections.
6. Security
- REACT-SEC-1 (MUST NOT): Use
dangerouslySetInnerHTMLwith untrusted, user-supplied content. If you must inject HTML (e.g. from a CMS), sanitize it first with a library such asDOMPurify. - REACT-SEC-2 (MUST NOT): Construct
href/srcprops from untrusted input without validation.javascript:URIs inhrefare an XSS vector. - REACT-SEC-3 (SHOULD NOT): Store sensitive data (tokens, PII) in component state or Context where it can be inspected via React DevTools. Use httpOnly cookies or a secure token store.
7. Testing
- REACT-TEST-1 (MUST): Test with React Testing Library (RTL) — test components through their rendered DOM and user interactions, not internal implementation details (state, refs, component instances). Use Vitest as the test runner in Vite projects; Jest is acceptable in CRA/webpack setups.
- REACT-TEST-2 (MUST): Maintain ≥ 80% coverage on changed files (same policy as all standards in this suite). Flag tests with no assertions or that only assert truthiness as inadequate.
- REACT-TEST-3 (SHOULD): Prefer
userEventoverfireEventfor simulating user interactions — it triggers the full browser event sequence (mousedown → mouseup → click, etc.) and is more realistic. - REACT-TEST-4 (SHOULD): Use
screenqueries (screen.getByRole,screen.getByLabelText) over container-based queries. Role-based queries are closest to how users and assistive technology perceive the UI. - REACT-TEST-5 (SHOULD): Mock only at system boundaries (HTTP, timers, browser APIs). Do not mock child components or internal hooks — that tests the mock, not the component.
// ✅ REACT-TEST-3 + REACT-TEST-4
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Button } from './Button';
test('calls onClick when clicked', async () => {
const onClick = vi.fn();
render(<Button label="Save" onClick={onClick} />);
await userEvent.click(screen.getByRole('button', { name: 'Save' }));
expect(onClick).toHaveBeenCalledOnce();
});8. Accessibility
- REACT-A11Y-1 (SHOULD): Use semantic HTML elements (
<button>,<nav>,<main>,<section>) rather than generic<div>/<span>with ARIA roles bolted on. - REACT-A11Y-2 (SHOULD): Every interactive element MUST be reachable and activatable via
keyboard. Do not attach click handlers to
<div>or<span>without anonKeyDownhandler andtabIndex. - REACT-A11Y-3 (SHOULD): All images MUST have an
altprop. Decorative images usealt="". Enable thejsx-a11yESLint plugin to catch violations at lint time.
9. Logging & Observability
Server-side/structured logging is owned by the runtime standard (
nodejs.md§8, ornextjs.mdfor the server tier). This section owns the client/browser slice, which no other standard covers.
- REACT-LOG-1 (MUST NOT): Leave debugging
console.log/console.debugcalls in committed or production client code (frontend mirror ofNODE-STYLE-7). Intentionalconsole.error/console.warnfor genuine error/warning paths is allowed; prefer routing them through a thin logger wrapper so output can be silenced or forwarded centrally. Enable theno-consoleESLint rule (allowingwarn/error) to enforce this. - REACT-LOG-2 (SHOULD): Route client-side errors and unhandled rejections to an
observability / error-tracking service (e.g. Sentry) rather than only
console. This generalizesREACT-ERR-1: the Error Boundary reports render errors, and a global handler captures the rest. - REACT-LOG-3 (MUST NOT): Log secrets, tokens, or PII to the browser console or client logs —
they are fully inspectable via DevTools and may be captured by third-party error trackers. This is
the logging counterpart to
REACT-SEC-3; scrub/deny-list sensitive fields before any client log or error report leaves the app.
10. Forms
- REACT-FORM-1 (SHOULD): For any non-trivial form (multiple fields, validation, or submission
state), use React Hook Form (
useForm) rather than hand-wiringuseStateper field. It keeps inputs uncontrolled by default, which minimizes re-renders. - REACT-FORM-2 (SHOULD): Validate with a Zod schema wired through
@hookform/resolvers/zod'szodResolver. Derive the form's TypeScript type from the schema withz.infer<typeof schema>— one source of truth for shape, validation, and types (this is the same Zod v4 choice locked intypescript.mdTS-TYPE-2). - REACT-FORM-3 (SHOULD): Drive submission through
handleSubmitand surface field errors from RHF'sformState.errors— do not roll a parallel error-tracking state alongside it.
// ✅ REACT-FORM-1/2/3: RHF + Zod, single source of truth
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod';
const schema = z.object({ name: z.string().min(1), age: z.number().int().positive() });
type FormValues = z.infer<typeof schema>;
function SignupForm() {
const { register, handleSubmit, formState: { errors } } =
useForm<FormValues>({ resolver: zodResolver(schema) });
return (
<form onSubmit={handleSubmit((data) => submitSignup(data))}>
<input {...register('name')} />
{errors.name && <span role="alert">{errors.name.message}</span>}
<input type="number" {...register('age', { valueAsNumber: true })} />
<button type="submit">Sign up</button>
</form>
);
}11. Styling
- REACT-STYLE-1 (SHOULD): Pick one styling approach (Tailwind CSS, CSS Modules, or a
CSS-in-JS library) and apply it consistently across the codebase. Mixing approaches without a
documented reason fragments the styling story and bloats the bundle. The concrete choice is
delegated to the project's
custom-standardsoverlay — this standard does not mandate one.
Resolved Decisions (v1.0)
| # | Question | Decision | Rule |
| 1 | State library default | Zustand SHOULD for global client state; Jotai acceptable; Redux Toolkit only for large/legacy; no library for trivial state | REACT-STATE-4 |
| 2 | Async/server state | TanStack Query SHOULD; bans useEffect+fetch cache patterns; Next.js App Router prefers Server Components | REACT-STATE-6 |
| 3 | Styling | Not mandated — one meta-rule (pick one, be consistent); concrete choice deferred to custom-standards | REACT-STYLE-1 |
| 4 | Forms | React Hook Form + Zod (zodResolver, z.infer) — reinforces TS-TYPE-2 | REACT-FORM-1/2/3 |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

