Cursorules are a powerful way to codify your team’s React component composition patterns. When configured correctly, they ensure that AI coding assistants generate consistent, maintainable components that align with your architecture. This guide walks you through creating effective Cursorules specifically designed for enforcing React component composition patterns across your team.
Why Component Composition Patterns Matter
React’s composition model gives developers flexibility in how they structure components. However, this flexibility can lead to inconsistency when multiple team members work on the same codebase. Without clear guidelines, you might encounter prop drilling, inconsistent component hierarchies, or mixed patterns for handling shared state.
Cursorules solve this problem by providing AI assistants with explicit instructions about your team’s preferred patterns. When an AI understands your composition conventions, it generates code that fits into your existing architecture.
The problem compounds as teams grow. A five-person team might handle inconsistency informally through code reviews. A twenty-person team cannot. When developers on different squads build features in parallel, diverging patterns create merge conflicts, confuse new hires, and slow down refactoring efforts. Cursorules act as a standing policy document that every AI-assisted session respects automatically, without requiring reviewers to catch every deviation.
Defining Your Component Composition Rules
Before writing Cursorules, document your team’s composition patterns. Consider these questions:
-
How do you handle prop drilling versus context?
-
What naming conventions do you use for compound components?
-
When do you prefer render props over hooks?
-
How do you structure component exports?
Once you have clear answers, translate them into Cursorules that AI assistants can follow.
A practical exercise: audit five recent components your team wrote and identify the patterns they share. If three out of five use compound components with Context for internal state, that is your preferred pattern. If naming conventions drift across those five, that inconsistency is exactly what Cursorules can lock down.
Creating Effective Cursorules
Here is an example of Cursorules designed to enforce compound component patterns:
# Cursorules for React Component Composition
## Compound Component Patterns
When creating components that need to share state between parent and children, use compound component patterns:
1. Use a parent component that manages state with React Context
2. Export child components as static properties of the parent
3. Use implicit state passing through Context
Example structure:
- ButtonGroup (parent, manages selected state)
- ButtonGroup.Button (child component)
- ButtonGroup.ButtonProps (optional, for TypeScript)
## Prop Naming Conventions
- Use 'children' for content slots, never 'content' or 'body'
- Prefix callback props with 'on' (onClick, onChange)
- Use 'is' or 'has' prefix for boolean props (isDisabled, hasError)
- Prefix internal props with underscore (_internalState)
## Component File Organization
Each component should follow this structure:
1. Type definitions (if TypeScript)
2. Context creation
3. Child component definitions
4. Parent component with composition
5. Named exports
## Forbidden Patterns
- Never use props.children for component logic
- Avoid passing components as props (use compound components instead)
- Don't create HOCs - prefer custom hooks
Enforcing Container-Presenter Pattern
Many teams adopt the container-presenter pattern for separating logic from presentation. Here is how to encode this in Cursorules:
## Container-Presenter Separation
When building features, separate concerns using containers and presenters:
Container responsibilities:
- Manage state and side effects
- Handle data fetching
- Pass raw data and callbacks to presenter
Presenter responsibilities:
- Receive data as props
- Handle UI logic only
- Be purely presentational when possible
Example:
// Container
function UserListContainer() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetchUsers().then(setUsers);
}, []);
return <UserListPresenter users={users} />;
}
// Presenter
function UserListPresenter({ users }) {
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
This pattern pairs well with testing strategies. Presenters are trivial to unit test because they are pure functions of their props. Containers can be tested separately using mocked data fetching. When Cursor generates code following this rule, your test coverage naturally improves alongside consistency.
Handling Component Composition in Custom Hooks
Custom hooks have become the preferred way to share logic in React applications. Your Cursorules should specify how AI assistants should create and use hooks:
## Custom Hooks Guidelines
1. Always prefix hook names with 'use' (useAuth, useFetch)
2. Return arrays for tuple-like data, objects for named properties
3. Document dependencies in comments when using useEffect
4. Handle loading and error states consistently
Example return pattern:
const { data, loading, error, refetch } = useUserData(userId);
An important nuance: hooks that manage a single value with a setter should return a tuple, like useState itself. Hooks that return multiple named properties should return an object. This distinction prevents destructuring confusion and makes call sites readable at a glance. Include this distinction explicitly in your Cursorules so the AI applies the right return shape automatically.
Structuring TypeScript Interfaces for Consistency
Teams using TypeScript benefit from encoding interface conventions in Cursorules. Without explicit guidance, AI assistants may generate redundant interfaces, misplace type definitions, or use inconsistent naming patterns across components.
Add a section like this to your Cursorules:
## TypeScript Interface Conventions
- Define component prop interfaces immediately above the component they describe
- Name prop interfaces as {ComponentName}Props (e.g., ButtonProps, ModalProps)
- Separate complex types into a dedicated Types.ts file if they are shared
- Prefer `interface` over `type` for object shapes
- Use `type` for unions, intersections, and primitive aliases
## Generic Component Patterns
When writing generic components, constrain type parameters:
- Prefer <T extends object> over unconstrained <T>
- Document generic parameters in JSDoc when the constraint is non-obvious
This prevents a common AI antipattern where Cursor generates a type Props = {} at the bottom of a file, inconsistent with where other interfaces live.
Testing Your Cursorules
After writing your Cursorules, test them by generating sample components. Ask your AI assistant to create a component following your rules, then verify:
-
Does it use compound components correctly?
-
Are naming conventions followed?
-
Is the file organization consistent?
-
Are forbidden patterns avoided?
Iterate on your Cursorules based on what the AI generates versus what you expect.
A systematic testing approach: create a checklist with one item per rule in your Cursorules file. After generating a test component, walk through the checklist item by item. Rules that the AI violates need either more specific wording or concrete examples. Rules the AI follows consistently can be marked stable. Treat Cursorules like code: they need testing and revision.
Sharing Cursorules Across Your Team
Place your Cursorules file in your project root as .cursorrules or .cursor/rules. Ensure every team member uses the same file by:
-
Adding it to version control
-
Documenting the location in your contribution guidelines
-
Reviewing it during onboarding new developers
Regular updates to your Cursorules should follow your standard code review process.
Consider treating Cursorules changes the same way you treat changes to your ESLint configuration. Both define coding standards; both warrant a PR, a short discussion, and explicit team sign-off. When a new pattern emerges organically in your codebase, a Cursorules update formalizes it and propagates it to every subsequent AI-assisted session automatically.
Example: Complete Cursorules File
# Project React Composition Guidelines
## Overview
This file defines our team's React component composition patterns.
All AI-generated code should follow these guidelines.
## Component Types
### Presentational Components
- Focus on UI only
- Receive data and callbacks as props
- No side effects or state (use useMemo/useCallback for optimization)
- Export as named exports
### Container Components
- Handle data fetching and state management
- Pass data to presentational components
- May use custom hooks internally
### Compound Components
- Use React Context for internal state
- Export child components as static properties
- Example: <Modal><Modal.Header /><Modal.Body /><Modal.Footer /></Modal>
## Props Pattern
```tsx
interface ButtonProps {
variant?: 'primary' | 'secondary' | 'danger';
size?: 'sm' | 'md' | 'lg';
isDisabled?: boolean;
onClick?: () => void;
children: React.ReactNode;
}
Import Order
- React imports
- External libraries
- Internal imports (absolute paths)
- Relative imports
- Type imports
File Naming
- Components: PascalCase (UserProfile.tsx)
- Hooks: camelCase with use prefix (useAuth.ts)
- Utilities: camelCase (formatDate.ts)
- Types: PascalCase (UserTypes.ts) ```
Keeping Cursorules Lean and Effective
One pitfall is writing Cursorules that are too long. If your rules file exceeds 200 lines, the AI assistant may weight early rules more heavily than later ones, or fail to apply all rules simultaneously. Keep each rule concise and actionable.
Prefer concrete examples over abstract descriptions. Instead of writing “use appropriate naming conventions,” write “name boolean props with is or has prefix: isDisabled, hasError, isLoading.” The more specific the instruction, the more reliably Cursor applies it.
Review your Cursorules quarterly. As React itself evolves — new hooks, new patterns, new best practices — your rules should evolve alongside it. A Cursorules file that references patterns from two years ago may actively guide the AI toward outdated approaches.
Related Articles
- Create CursorRules That Enforce Your Team’s Git Commit
- Create CursorRules That Teach Cursor Your Team’s State
- Writing Effective CursorRules for React TypeScript Projects
- How to Use AI to Help Devrel Teams Create Video Tutorial Scr
- How to Use AI to Help Sre Teams Create on Call Handoff Docum
Built by theluckystrike — More at zovo.one