best-practices-react
React, Next.js, React Native, and web design best practices from Vercel Engineering. Use when writing, reviewing, or refactoring React/Next.js/React Native components, optimizing performance, auditing UI accessibility, or designing component APIs. Triggers: "review react", "optimize component", "check accessibility", "react best practices", "component architecture", "react native performance".
- License 许可
- MIT
- 最近更新
- 2026-06-13
- Stars
- ★ 0
- Forks
- 2
01 前言 Front Matter
- name
- best-practices-react
- license
- MIT
- composes
- [ "task-monitor" ]
- metadata
- { "author": "vercel", "version": "1.0.0", "language": "typescript" }
- provides
- [ "best-practices-react" ]
- triggers
- [ "best practices react", "react review", "react component", "next.js", "react native", "component architecture" ]
- description
- React, Next.js, React Native, and web design best practices from Vercel Engineering. Use when writing, reviewing, or refactoring React/Next.js/React Native components, optimizing performance, auditing UI accessibility, or designing component APIs. Triggers: "review react", "optimize component", "check accessibility", "react best practices", "component architecture", "react native performance".
02 资源文件 12
- 参考文档.github/workflows/react-best-practices-ci.yml822 B
- 参考文档docs/AGENTS.md3.2 KB
- 参考文档docs/README.md4.5 KB
- 参考文档packages/react-best-practices-build/pnpm-lock.yaml10.0 KB
- 脚本packages/react-best-practices-build/src/build.ts9.7 KB
- 脚本packages/react-best-practices-build/src/config.ts2.8 KB
- 脚本packages/react-best-practices-build/src/extract-tests.ts2.4 KB
- 脚本packages/react-best-practices-build/src/migrate.ts5.4 KB
- 脚本packages/react-best-practices-build/src/parser.ts7.7 KB
- 脚本packages/react-best-practices-build/src/types.ts1.3 KB
- 脚本packages/react-best-practices-build/src/validate.ts3.5 KB
- 脚本sanity.sh1.3 KB
03 SKILL.md 正文
React Best Practices Collection
Enterprise-grade React/Next.js/React Native rules from Vercel Engineering. 100+ rules across 4 sub-skills with impact-prioritized categories.
Sub-Skills
| Sub-Skill | Rules | Focus |
|---|---|---|
react-best-practices |
40+ | React/Next.js performance optimization |
web-design-guidelines |
100+ | Accessibility, forms, animation, dark mode, i18n |
react-native-skills |
16 | Mobile performance, animations, platform APIs |
composition-patterns |
8+ | Component architecture, prop design, compound components |
When to Use
- react-best-practices: Writing React components, Next.js pages, data fetching, bundle optimization
- web-design-guidelines: UI review, accessibility audit, design compliance, UX check
- react-native-skills: React Native/Expo apps, mobile performance, native modules
- composition-patterns: Refactoring boolean prop proliferation, building component libraries
Quick Reference
Critical Impact — NON-NEGOTIABLE
Every interactive element gets 4 things at write time — no exceptions, no retrofitting:
data-qid— stable CSS selector. Format:component:element:qualifier(colon-separated). Used by test manifests, CDP automation, andverify-data-qid.pyenforcement.data-qs-action— QuerySpec action ID for agent/voice execution. Format:COMPONENT_ACTION(uppercase, underscore). An agent resolves NL intent → action ID →document.querySelector('[data-qs-action="APPROVE_ENTRY"]').click()— zero latency, no database lookup, works offline.title— human-readable label. Required for MIL-STD-1472H compliance, screen readers, tooltips.useRegisterAction— registers the action to ArangoDBapp_actionscollection for training data, analytics, and cross-app action discovery.
Components without all 4 are not shippable. verify-data-qid.py enforces data-qid coverage in CI.
Write-time checklist:
<button
data-qid="quarantine:action:approve"
data-qs-action="QUARANTINE_APPROVE"
title="Approve selected entry"
onClick={() => handleAction(id, 'approve')}
>
Approve
</button>
// In component body (registers to ArangoDB app_actions for training flywheel):
useRegisterAction('quarantine:action:approve', {
app: 'datalake-explorer',
action: 'QUARANTINE_APPROVE',
label: 'Approve',
description: 'Approve quarantined entry and remove from queue',
})
Why both data-qs-action AND useRegisterAction?
data-qs-action= runtime DOM introspection (agent clicks the element, zero latency)useRegisterAction= ArangoDB registry (training data, cross-app discovery, analytics)- They use the SAME action ID (
QUARANTINE_APPROVE) so intent → action → DOM click is one straight line
Enforcement: verify-data-qid.py MUST run in CI and /plan DoD for any UX task. Exit 1 = not shippable. /review-plan MUST FAIL any UX plan without it.
- Eliminate request waterfalls (parallel fetching,
Promise.all) - Bundle size (dynamic imports, tree shaking, barrel file avoidance)
- Accessibility (aria-labels, semantic HTML, keyboard navigation)
- FlashList over FlatList (React Native)
High Impact
- Server-side rendering and streaming
- Focus states (
focus-visiblepatterns) - Layout (flex patterns, safe areas)
- Animation (Reanimated,
prefers-reduced-motion)
Medium Impact
- Re-render optimization (
useMemo,useCallback, React Compiler) - Forms (autocomplete, validation, error handling)
- Dark mode (
color-scheme,theme-colormeta) - State management (Zustand patterns)
File Structure
best-practices-react/
├── SKILL.md # This file
├── README.md # Detailed sub-skill descriptions
├── CLAUDE.md # Agent guidance (skill creation)
├── skills/
│ ├── react-best-practices/ # React/Next.js performance rules
│ │ ├── SKILL.md
│ │ └── rules/ # Atomic rule files
│ ├── web-design-guidelines/ # UI/UX/a11y rules
│ │ ├── SKILL.md
│ │ └── rules/
│ ├── react-native-skills/ # React Native/Expo rules
│ │ ├── SKILL.md
│ │ └── rules/
│ ├── composition-patterns/ # Component architecture rules
│ │ ├── SKILL.md
│ │ └── rules/
│ └── claude.ai/
│ └── vercel-deploy-claimable/ # Vercel deployment skill
└── packages/
└── react-best-practices-build/ # TypeScript build tooling
Common Mistakes
WRONG: useRegisterAction inside JSX, .map(), or function params
// BROKEN — hook inside .map() callback (violates Rules of Hooks)
{items.map((item) => {
useRegisterAction('list:item', { ... }) // ← CRASH or silent failure
return <div>{item.name}</div>
})}
// BROKEN — hook inside function parameter destructuring
function MetaItem({
useRegisterAction('meta:item', { ... }) // ← syntax error
label,
value,
}: Props) { ... }
RIGHT: useRegisterAction at top of component function body
export default function QuarantineView({ entries }: Props) {
// Hooks FIRST — before any other code
useRegisterAction('quarantine:action:approve', { ... })
useRegisterAction('quarantine:action:reject', { ... })
const [selected, setSelected] = useState(null)
// ... rest of component
Why: React hooks must be called at the top level of a function component. Mechanical instrumentation scripts that inject hooks by line number will place them inside JSX or callbacks. Always verify placement manually.
WRONG: Import paths verified only by tsc --noEmit
npx tsc --noEmit # exit 0 — "TypeScript clean!"
# But Vite dev server shows: Failed to resolve import "../../../hooks/useRegisterAction"
RIGHT: Verify imports against the live Vite dev server
# TSC and Vite resolve paths differently. Always check Vite:
curl -s -o /dev/null -w "%{http_code}" "http://localhost:3002/src/components/MyComponent.tsx"
# 200 = compiles. 500 = broken import. Do this for EVERY modified file.
Why: moduleResolution: "bundler" in tsconfig means TSC skips resolution for some imports. Vite resolves them at serve time and will 500 on wrong relative paths. A file can pass tsc --noEmit and still crash in the browser.
WRONG: Test manifest generated from grep of TSX source files
# Grepping source finds 124 data-qid values. But 91 of them are inside
# modals, dropdowns, and subcomponents that only render after user interaction.
grep -roh 'data-qid="[^"]*"' src/components/ | sort -u # ← 124 qids
# Live DOM on page load has only 33. The other 91 don't exist yet.
RIGHT: Generate test manifest from the live DOM via CDP
# Use /test-interactions generate, or query the live DOM directly:
./run.sh generate --url "http://localhost:3002/#my-view" --output manifest.json
# Or via CDP JavaScript execution:
# document.querySelectorAll('[data-qid]') on EACH tab/view state
Why: Components render conditionally. A data-qid in TSX source only exists in the DOM when that component is mounted. Test manifests must reflect what the user can actually see and click, not what exists in source code.
WRONG: Static data-qid on dynamic list items
// Every entry gets the same qid — selector matches multiple elements
{entries.map(e => (
<div data-qid="quarantine:entry" onClick={() => select(e.id)}>
{e.name}
</div>
))}
RIGHT: Dynamic data-qid with stable identifier
{entries.map(e => (
<div data-qid={`quarantine:entry:${e.id}`} onClick={() => select(e.id)}>
{e.name}
</div>
))}
Why: Test manifests need unique selectors. If 18 entries share data-qid="quarantine:entry", querySelector always hits the first one. Use the entity ID to make each qid unique. Note: dynamic qids change when data changes, so test manifests for list items must query the live DOM or use :nth-child fallbacks.
WRONG: Early return that hides chrome (filters, nav, controls) on empty state
// The entire component disappears — user can't switch filters to find entries
if (!loading && entries.length === 0) {
return <div>Queue is empty</div> // ← filter buttons, layout controls GONE
}
RIGHT: Empty state renders inline inside the content area
const showEmptyState = !loading && entries.length === 0
return (
<div>
<FilterBar /> {/* always visible */}
<LayoutControls /> {/* always visible */}
{showEmptyState
? <EmptyMessage>No entries for this filter</EmptyMessage>
: <EntryList entries={filtered} />
}
</div>
)
Why: Early returns that replace the whole component break interaction tests — filter/layout data-qid elements vanish from the DOM when the list is empty. The user also loses the ability to switch filters or change layout. Chrome (nav, filters, controls) must always render; only the content area should show empty state.
WRONG: Importing from barrel files that bundle the entire module
import { Button } from '@/components'; // barrel re-export, bundles everything
RIGHT: Import directly from the component file
import { Button } from '@/components/Button';
WRONG: Missing focus-visible styles on interactive elements
button:focus { outline: 2px solid blue; } /* triggers on click too */
RIGHT: Use focus-visible for keyboard-only focus indicators
button:focus-visible { outline: 2px solid blue; }
WRONG: Sequential data fetching (request waterfall)
const user = await fetchUser(id);
const posts = await fetchPosts(user.id); // waits for user first
RIGHT: Parallel fetching with Promise.all
const [user, posts] = await Promise.all([fetchUser(id), fetchPosts(id)]);
04 同仓库更多 Skills
best-practices-streamdeck
Project-specific best practices for the Stream Deck control suite: icon format constraints, socket vs config boundaries, widget button lifecycle, page creation via build_page, ArangoDB fallback patterns, and NVIS palette compliance.
best-practices-scillm
Error recovery and anti-patterns for scillm LLM proxy. Load this when scillm calls fail, timeout, or return unexpected results. Covers batch sizing, header requirements, model selection, and debugging workflow.
best-practices-rust
Repo-specific Rust best practices for agentic coding: thiserror + anyhow error handling, tokio async runtime, tracing for observability, clap for CLI, axum for HTTP, serde patterns, cargo workspace conventions, ownership and lifetimes, and idiomatic Rust 2024 edition patterns.
react-native-skills
React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.
react-best-practices
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
composition-patterns
React composition patterns that scale. Use when refactoring components with boolean prop proliferation, building flexible component libraries, or designing reusable APIs. Triggers on tasks involving compound components, render props, context providers, or component architecture. Includes React 19 API changes.