react-patterns
Skill6 starsChanged 8 months agoMITView on GitHub
Guide React component architecture — composition patterns, custom hooks, props design, state management, and error boundaries. Use this skill whenever the user is designing React components, refactoring component structure, creating custom hooks, deciding how to manage state, working with context providers, building form components, or asking about React best practices and patterns. Also trigger when the user mentions component composition, render props, compound components, controlled vs uncontrolled components, or lifting state.
38 other projects use a version of this.
Adopted by
Most recently taken up by
- lhbsaa/apex-unifiedtheir own version, first seen Nov 8, 2026
- reddygopalkrishna/developer-agent-skillstheir own version, first seen Nov 8, 2026
- komluk/scaffoldingtheir own version, first seen Nov 7, 2026
- Lukk17/agent-standardstheir own version, first seen Nov 7, 2026
- ku5ic/claude-kittheir own version, first seen Nov 4, 2026
- renepf/claude-skillstheir own version, first seen Oct 25, 2026
Used with
Projects with it also use typescript-patterns, typescript-strict and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
cohen-lielSkilltypescript-patterns
TypeScript best practices and patterns. Use when writing TypeScript code, defining types, working with generics, or converting JavaScript to TypeScript.
Also in 3 projects that use this
MicrosoftSkilltypescript-strict
Enable TypeScript strict mode (strict, noImplicitAny, strictNullChecks, etc.) in a project and fix the resulting errors without weakening types, tests, or runtime behavior. Use when asked to "enable strict mode", "turn on TypeScript strict", "fix strict errors", or migrate a codebase to strict type checking.
Also in 3 projects that use this
xfstudioSkilldocker-expert
Docker containerization expert with deep knowledge of multi-stage builds, image optimization, container security, Docker Compose orchestration, and production deployment patterns. Use PROACTIVELY for Dockerfile optimization, container issues, image size problems, security hardening, networking, and orchestration challenges.
Also in 3 projects that use this
LangChainSkilldocker-patterns
Best practices for Docker containerization and multi-stage builds
Also in 4 projects that use this
BlockSkilltesting-strategy
Guidelines for writing effective tests in this project
Also in 4 projects that use this
LangChainSkilldatabase-migrations
Database migration patterns and schema versioning
Also in 4 projects that use this
Other versions38 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 38
- openstory-so/openstory★ 696same name
- involvex/youtube-music-cli★ 477same name
- xenitV1/Antigravity-Workflows★ 130same name
- TangleML/tangle-ui★ 104same name
- maxyeh0817/Forge★ 34same name
- VoDaiLocz/kilo-kit-mcp★ 28same name
- Fandry96/k3-agentic-skills★ 27same name
- komluk/scaffolding★ 16same name
- xfstudio/skills★ 9same name
- gongyijie85/dsh-ecc★ 8same name
28 more not listed
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 repository20 other files it gives its agents.
- a11y-auditSkill
- design-an-interfaceSkill
- edit-articleSkill
- find-skillsSkill
- grill-meSkill
- improve-codebase-architectureSkill
- nextjs-architectSkill
- perf-optimizerSkill
- prd-to-issuesSkill
- request-refactor-planSkill
- seo-auditSkill
- solana-devSkill
- tddSkill
- triage-issueSkill
- write-a-prdSkill
- write-a-skillSkill
- docxSkill
- frontend-designSkill
- mcp-builderSkill
- skill-creatorSkill
The file
We split this skill into the rules it gives an agent
6 rules. 0 are common, 4 are distinctive, and 2 are very specific to this project.
0
Common
Most of the 34 edited versions we read keep these.
4
Distinctive
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 14
Instead of a component with many conditional props, compose smaller focused components together.
- Distinctive: line 48
Use compound components when a group of components share implicit state and always work together (tabs, accordions, selects, menus).
- Very specific: line 179
Use children for most cases — it's simpler and more readable.
- Distinctive: line 180
Use render props (or render function children) when the child needs data from the parent:
- Very specific: line 233
Always prefix with use
- Distinctive: line 340
Place error boundaries around independent sections so a failure in one area doesn't crash everything:
“Common” is measured: kept by at least 6 in 10 of the 34 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
React Component Patterns
Help users write well-structured React components with clean composition, proper state management, and maintainable patterns. Assumes Next.js + Tailwind CSS environment.
Component Composition
Prefer composition over props overload
Instead of a component with many conditional props, compose smaller focused components together.
Avoid — prop-heavy monolith:
<Card
title="Revenue"
subtitle="Monthly"
icon="chart"
showBorder
variant="highlighted"
headerAction={<Button>Export</Button>}
footer={<Link>View details</Link>}
/>Prefer — composable parts:
<Card>
<Card.Header>
<Card.Title>Revenue</Card.Title>
<Card.Subtitle>Monthly</Card.Subtitle>
<Button>Export</Button>
</Card.Header>
<Card.Body>
<RevenueChart data={data} />
</Card.Body>
<Card.Footer>
<Link href="/revenue">View details</Link>
</Card.Footer>
</Card>Compound Components
Use compound components when a group of components share implicit state and always work together (tabs, accordions, selects, menus).
"use client"
import { createContext, useContext, useState, type ReactNode } from 'react'
type TabsContextType = { activeTab: string; setActiveTab: (id: string) => void }
const TabsContext = createContext<TabsContextType | null>(null)
function useTabs() {
const ctx = useContext(TabsContext)
if (!ctx) throw new Error('Tab components must be used within <Tabs>')
return ctx
}
function Tabs({ defaultTab, children }: { defaultTab: string; children: ReactNode }) {
const [activeTab, setActiveTab] = useState(defaultTab)
return (
<TabsContext.Provider value={{ activeTab, setActiveTab }}>
<div>{children}</div>
</TabsContext.Provider>
)
}
function TabList({ children }: { children: ReactNode }) {
return <div className="flex gap-1 border-b border-gray-200">{children}</div>
}
function Tab({ id, children }: { id: string; children: ReactNode }) {
const { activeTab, setActiveTab } = useTabs()
return (
<button
onClick={() => setActiveTab(id)}
className={`px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors ${
activeTab === id
? 'border-blue-600 text-blue-600'
: 'border-transparent text-gray-500 hover:text-gray-700'
}`}
>
{children}
</button>
)
}
function TabPanel({ id, children }: { id: string; children: ReactNode }) {
const { activeTab } = useTabs()
if (activeTab !== id) return null
return <div className="py-4">{children}</div>
}
Tabs.List = TabList
Tabs.Tab = Tab
Tabs.Panel = TabPanel
export { Tabs }Usage:
<Tabs defaultTab="overview">
<Tabs.List>
<Tabs.Tab id="overview">Overview</Tabs.Tab>
<Tabs.Tab id="analytics">Analytics</Tabs.Tab>
</Tabs.List>
<Tabs.Panel id="overview">Overview content</Tabs.Panel>
<Tabs.Panel id="analytics">Analytics content</Tabs.Panel>
</Tabs>Props Design
Keep props interfaces focused
Each component should accept only the props it needs. Use TypeScript to be explicit:
interface UserCardProps {
name: string
email: string
avatarUrl?: string
role: 'admin' | 'member' | 'viewer'
}
export function UserCard({ name, email, avatarUrl, role }: UserCardProps) {
// ...
}Spread HTML attributes for wrapper components
For components that wrap native elements, extend the native element's props:
import { type ButtonHTMLAttributes, forwardRef } from 'react'
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'ghost'
size?: 'sm' | 'md' | 'lg'
}
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ variant = 'primary', size = 'md', className, children, ...props }, ref) => {
const base = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors'
const variants = {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
ghost: 'text-gray-600 hover:bg-gray-100',
}
const sizes = {
sm: 'px-3 py-1.5 text-sm',
md: 'px-4 py-2 text-sm',
lg: 'px-6 py-3 text-base',
}
return (
<button
ref={ref}
className={`${base} ${variants[variant]} ${sizes[size]} ${className ?? ''}`}
{...props}
>
{children}
</button>
)
}
)
Button.displayName = 'Button'
export { Button }children vs render props
- Use
childrenfor most cases — it's simpler and more readable. - Use render props (or render function children) when the child needs data from the parent:
<DataLoader url="/api/users">
{({ data, isLoading }) =>
isLoading ? <Skeleton /> : <UserList users={data} />
}
</DataLoader>Custom Hooks
Extract logic, not JSX
Custom hooks should encapsulate stateful logic and side effects, returning values and callbacks — not components.
function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState(value)
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay)
return () => clearTimeout(timer)
}, [value, delay])
return debouncedValue
}function useLocalStorage<T>(key: string, initialValue: T) {
const [storedValue, setStoredValue] = useState<T>(() => {
if (typeof window === 'undefined') return initialValue
try {
const item = window.localStorage.getItem(key)
return item ? JSON.parse(item) : initialValue
} catch {
return initialValue
}
})
const setValue = (value: T | ((val: T) => T)) => {
const valueToStore = value instanceof Function ? value(storedValue) : value
setStoredValue(valueToStore)
window.localStorage.setItem(key, JSON.stringify(valueToStore))
}
return [storedValue, setValue] as const
}Hook naming conventions
- Always prefix with
use - Name should describe what data/behavior it provides:
useAuth,useMediaQuery,useClickOutside - Return consistent shapes:
[value, setter]for simple state,{ data, error, isLoading }for async
State Management
Start simple, scale as needed
- Local state (useState) — for state that belongs to one component
- Lifted state — when a sibling needs access, lift to the nearest common parent
- Context — for state shared across a subtree (theme, auth, locale)
- URL state (searchParams) — for state that should be shareable/bookmarkable (filters, pagination, tabs)
- External store (Zustand, Jotai) — for complex client-side state shared across many components
Context — avoid the "god provider" anti-pattern
Split contexts by domain rather than creating one massive AppContext:
// Separate concerns into focused providers
<AuthProvider>
<ThemeProvider>
<ToastProvider>
{children}
</ToastProvider>
</ThemeProvider>
</AuthProvider>Each provider manages its own slice of state. Components only subscribe to the contexts they need, which avoids unnecessary re-renders.
URL state for user-facing state
Filters, sort order, pagination, and active tabs should live in the URL so users can share and bookmark views:
"use client"
import { useSearchParams, useRouter, usePathname } from 'next/navigation'
function useQueryState(key: string, defaultValue: string) {
const searchParams = useSearchParams()
const router = useRouter()
const pathname = usePathname()
const value = searchParams.get(key) ?? defaultValue
const setValue = (newValue: string) => {
const params = new URLSearchParams(searchParams.toString())
if (newValue === defaultValue) {
params.delete(key)
} else {
params.set(key, newValue)
}
router.replace(`${pathname}?${params.toString()}`)
}
return [value, setValue] as const
}Controlled vs Uncontrolled Components
Support both patterns
Build form components that work controlled (parent owns the state) or uncontrolled (component owns its own state via defaultValue):
interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
label: string
error?: string
}
export function Input({ label, error, id, ...props }: InputProps) {
const inputId = id ?? label.toLowerCase().replace(/\s+/g, '-')
return (
<div>
<label htmlFor={inputId} className="block text-sm font-medium text-gray-700 mb-1">
{label}
</label>
<input
id={inputId}
className={`w-full px-3 py-2 border rounded-lg text-sm transition-colors
${error
? 'border-red-500 focus:ring-red-500'
: 'border-gray-300 focus:ring-blue-500'
} focus:outline-none focus:ring-2`}
{...props}
/>
{error && <p className="mt-1 text-sm text-red-600">{error}</p>}
</div>
)
}Works both ways:
// Controlled
<Input label="Email" value={email} onChange={e => setEmail(e.target.value)} />
// Uncontrolled
<Input label="Email" defaultValue="user@example.com" />Error Boundaries
Wrap sections, not the entire app
Place error boundaries around independent sections so a failure in one area doesn't crash everything:
"use client"
import { Component, type ReactNode } from 'react'
interface Props {
children: ReactNode
fallback?: ReactNode
}
interface State {
hasError: boolean
error: Error | null
}
export class ErrorBoundary extends Component<Props, State> {
state: State = { hasError: false, error: null }
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error }
}
render() {
if (this.state.hasError) {
return this.props.fallback ?? (
<div className="p-4 bg-red-50 border border-red-200 rounded-lg">
<p className="text-red-800 font-medium">Something went wrong</p>
<p className="text-red-600 text-sm mt-1">{this.state.error?.message}</p>
</div>
)
}
return this.props.children
}
}Usage:
<div className="grid grid-cols-2 gap-4">
<ErrorBoundary fallback={<WidgetError />}>
<RevenueChart />
</ErrorBoundary>
<ErrorBoundary fallback={<WidgetError />}>
<UserActivity />
</ErrorBoundary>
</div>Lists and Keys
Use stable, unique identifiers as keys
// Good — stable ID from data
{users.map(user => <UserCard key={user.id} user={user} />)}
// Avoid — index as key (breaks with reordering, insertion, deletion)
{users.map((user, i) => <UserCard key={i} user={user} />)}Index keys are acceptable only for static lists that never change order.
Conditional Rendering
Keep it readable
// Simple boolean — use &&
{isAdmin && <AdminPanel />}
// Binary choice — use ternary
{isLoading ? <Skeleton /> : <Content data={data} />}
// Multiple conditions — use early returns or a mapping
function StatusBadge({ status }: { status: 'active' | 'pending' | 'inactive' }) {
const styles = {
active: 'bg-green-100 text-green-800',
pending: 'bg-yellow-100 text-yellow-800',
inactive: 'bg-gray-100 text-gray-800',
}
return (
<span className={`px-2 py-1 text-xs font-medium rounded-full ${styles[status]}`}>
{status}
</span>
)
}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.

