skills/mine/react/SKILL.md
Comprehensive React development guide covering component architecture, hooks, state management, TypeScript integration, useEffect patterns, and testing with Vitest. Use when creating React components, custom hooks, managing state, or any frontend React code. Essential for React 19+ development. Don't use for React Native, non-React frameworks (Vue, Svelte, Solid), or backend-only Node.js code.
npx skillsauth add pedronauck/skills reactInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill provides comprehensive guidelines, patterns, and best practices for React development in this project.
references/best-practices.mdbutton, input, a, …), extend that element’s props (React.ComponentProps<"…">) and spread ...props — see Extend native element props below and references/best-practices.md → Extending HTML Elements.references/useeffect-patterns.mdtanstack skilltanstack skilluse(), Actions, useOptimistic())Default rule for wrappers: whenever a component’s root output is a single native element, its props interface MUST extend that element’s intrinsic props — same contract as shadcn/ui-generated primitives. Callers keep access to aria-*, data-*, onClick, disabled, etc., without bespoke passthrough lists.
Do this:
| Requirement | Detail |
| ------------- | ------ |
| Base type | interface XProps extends React.ComponentProps<"button"> (or "input", "a", "div", …) |
| Spreading | Destructure your custom fields, then {...props} (and merged className) onto the DOM node |
| Ref | Use React.forwardRef and the matching element ref type when refs are needed |
interface TextFieldProps extends React.ComponentProps<"input"> {
label: string;
error?: string;
}
function TextField({ label, error, className, ...props }: TextFieldProps) {
return (
<label className="flex flex-col gap-1">
<span>{label}</span>
<input className={cn("rounded border px-2 py-1", error && "border-destructive", className)} {...props} />
{error ? <span className="text-destructive text-sm">{error}</span> : null}
</label>
);
}
Variants + CVA: if you use class-variance-authority, combine intrinsic props with VariantProps<typeof variants> (often extends React.ButtonHTMLAttributes<HTMLButtonElement>). Follow the shadcn skill patterns.
Deep dive: references/best-practices.md → Extending HTML Elements.
| Priority | Tool | Use Case |
|----------|------|----------|
| 1 | useState/useReducer | Component-specific UI state |
| 2 | Zustand | Shared client state across components |
| 3 | TanStack Query | Server state and data synchronization |
| 4 | URL state | Shareable application state (TanStack Router) |
| Situation | DON'T | DO |
|-----------|-------|-----|
| Derived state from props/state | useState + useEffect | Calculate during render |
| Expensive calculations | useEffect to cache | useMemo |
| Reset state on prop change | useEffect with setState | key prop |
| User event responses | useEffect watching state | Event handler directly |
| Notify parent of changes | useEffect calling onChange | Call in event handler |
| Fetch data | useEffect without cleanup | useEffect with cleanup OR TanStack Query |
useSyncExternalStore when possible)const fullName = firstName + ' ' + lastName// CORRECT: Type props directly (never use React.FC)
interface BrandButtonProps {
variant: "primary" | "secondary";
children: React.ReactNode;
}
function BrandButton({ variant, children }: BrandButtonProps) {
return <button type="button" className={variant}>{children}</button>;
}
// When wrapping a native element, extend its props — see "Extend native element props" above
interface IconButtonProps extends React.ComponentProps<"button"> {
icon: React.ReactNode;
}
useXxx pattern// State-like hook returns array
function useToggle(initial = false) {
const [value, setValue] = useState(initial);
const toggle = useCallback(() => setValue((v) => !v), []);
return [value, toggle] as const;
}
// Complex hook returns object
function useUser(id: string) {
const query = useQuery({ queryKey: ["user", id], queryFn: () => fetchUser(id) });
return {
user: query.data,
isLoading: query.isLoading,
error: query.error,
refetch: query.refetch,
};
}
// CORRECT: Hook handles all logic, component handles rendering
function useIssueSearch(projectId: string) {
const [query, setQuery] = useState("");
const [filters, setFilters] = useState<Filters>({});
const issues = useQuery({
queryKey: ["issues", projectId, query, filters],
queryFn: () => searchIssues(projectId, query, filters),
});
return {
query,
setQuery,
filters,
setFilters,
issues: issues.data ?? [],
isLoading: issues.isLoading,
};
}
function IssueList({ projectId }: { projectId: string }) {
const { query, setQuery, issues, isLoading } = useIssueSearch(projectId);
return (
<div>
<SearchInput value={query} onChange={setQuery} />
{isLoading ? <Loading /> : <IssueTable issues={issues} />}
</div>
);
}
| Type | Pattern | Example |
|------|---------|---------|
| Components | kebab-case.tsx | user-avatar.tsx |
| Hooks | use-kebab-case.ts | use-user-data.ts |
| Utilities | camelCase.ts | formatDate.ts |
| Types | types.ts | types.ts |
| Tests | *.test.tsx | user-avatar.test.tsx |
import { describe, it, expect, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import { renderHook, act } from "@testing-library/react";
describe("MyComponent", () => {
it("renders correctly", () => {
render(<MyComponent />);
expect(screen.getByText("Hello")).toBeInTheDocument();
});
});
describe("useMyHook", () => {
it("returns expected value", () => {
const { result } = renderHook(() => useMyHook());
expect(result.current.value).toBe(expected);
});
});
Before finishing a task involving React:
React.FC); native wrappers extend React.ComponentProps<"…"> (or ButtonHTMLAttributes + variants per shadcn skill) and forward ...propspnpm run lint, pnpm run typecheck, and pnpm run testFor comprehensive guidance, consult these reference files:
references/best-practices.md - Component architecture, TypeScript, state management, React 19+ features, testing patternsreferences/useeffect-patterns.md - When to use/avoid useEffect, anti-patterns, and better alternativesdevelopment
Deep review of branch diffs, working trees, or GitHub PRs at any size. Use when the user asks for CodeRabbit-grade review, an incremental re-review after new pushes, publication of findings to a PR, a cross-LLM peer-review verdict round, or conformance review against spec artifacts. Don't use for applying fixes, reviewing specs or PRDs as documents, or quick single-file feedback.
tools
Orchestrate Claude and Codex worker TUIs from a controller agent through herdr panes and the herdr socket CLI. Use when delegating bounded tasks to herdr worker panes, running user-activated plan-first delegations (Claude Code plan mode, Codex Plan mode), waiting on native agent status (idle, working, blocked, done), or verifying worker reports. Workers launch as interactive TUIs via herdr agent start — never through headless runners (compozy exec, claude -p, codex exec). Not for cmux workspaces (see cmux-orchestration) and not for end-user herdr control.
tools
TanStack Query, Router, and Form patterns for React. Use when writing useQuery/queryOptions, mutations, caching, file-based routes, search params, loaders, or TanStack Form validation. Don't use for TanStack Start, TanStack DB/collections, Zustand client state, or non-TanStack routing.
development
Use when the user wants to design, redesign, shape, critique, audit, polish, clarify, distill, harden, optimize, adapt, animate, colorize, extract, or otherwise improve a frontend interface. Covers websites, landing pages, dashboards, product UI, app shells, components, forms, settings, onboarding, and empty states. Handles UX review, visual hierarchy, information architecture, cognitive load, accessibility, performance, responsive behavior, theming, anti-patterns, typography, fonts, spacing, layout, alignment, color, motion, micro-interactions, UX copy, error states, edge cases, i18n, and reusable design systems or tokens. Also use for bland designs that need to become bolder or more delightful, loud designs that should become quieter, live browser iteration on UI elements, or ambitious visual effects that should feel technically extraordinary. Not for backend-only or non-UI tasks.