cursor-handbook / frontend
girijashankarj/cursor-handbook/.cursor/rules/frontend/component-patterns.mdc
Frontend component architecture and patterns. Apply when creating or editing UI components.
Cursor rule30 starsChanged 31 days ago
---
description: "Frontend component architecture and patterns. Apply when creating or editing UI components."
alwaysApply: false
globs: "**/*.tsx,**/*.jsx,**/components/**/*,**/Components/**/*"
---
# Frontend Component Patterns
## Component Structure
```
src/components/
├── ui/ # Atomic/base components
│ ├── Button/
│ │ ├── Button.tsx
│ │ ├── Button.test.tsx
│ │ ├── Button.stories.tsx
│ │ └── index.ts
│ ├── Input/
│ └── Modal/
├── features/ # Feature-specific components
│ ├── Auth/
│ ├── Dashboard/
│ └── Settings/
├── layout/ # Layout components
│ ├── Header/
│ ├── Sidebar/
│ └── Footer/
└── shared/ # Shared/utility components
├── ErrorBoundary/
├── LoadingSpinner/
└── ProtectedRoute/
```
## Component Guidelines
### Functional Components Only
- Use functional components with hooks — no class components
- Use `React.FC` or explicit return types
- Destructure props at the function signature level
### Props
- Define props interface above the component
- Use descriptive prop names
- Provide default values where appropriate
- Document complex props with JSDoc comments
```tsx
interface ButtonProps {
/** Button label text */
label: string;
/** Visual style variant */
variant?: 'primary' | 'secondary' | 'danger';
/** Disabled state */
disabled?: boolean;
/** Click handler */
onClick: () => void;
}
export const Button: React.FC<ButtonProps> = ({
label,
variant = 'primary',
disabled = false,
onClick,
}) => {
return (
<button
className={`btn btn-${variant}`}
disabled={disabled}
onClick={onClick}
>
{label}
</button>
);
};
```
### State Management
- Local state: `useState` for component-scoped state
- Shared state: Context API or state library (Zustand, Redux Toolkit)
- Server state: React Query / TanStack Query
- Form state: React Hook Form or Formik
- **NEVER** prop-drill more than 2 levels — use context or state management
### Performance
- Memoize expensive computations with `useMemo`
- Memoize callbacks with `useCallback` when passing to child components
- Use `React.memo` for pure presentational components
- Lazy load routes and heavy components with `React.lazy`
- Virtualize long lists (react-window or react-virtuoso)
## Styling Rules
- Use CSS Modules, Tailwind CSS, or styled-components — pick one, be consistent
- No inline styles except for dynamic values
- Follow design system tokens for colors, spacing, typography
- Mobile-first responsive design
- Support dark mode via CSS variables or theme context
## Anti-patterns
- Don't use `any` for props — define explicit interface
```tsx
// BAD
const Button = (props: any) => ...
// GOOD
interface ButtonProps { label: string; onClick: () => void; }
```
- Don't fetch in useEffect without cleanup — cancel on unmount
- Don't put server data in global state — use React Query
- Don't use index as key when list can reorder — use stable id
- Don't inline object/array in JSX — causes unnecessary re-renders
## Examples
```tsx
// BAD: New object every render
<Child onClick={() => ({})} />
// GOOD: Stable callback
const noop = useCallback(() => {}, []);
<Child onClick={noop} />
```
## Edge Cases
- **Loading states**: Skeleton > spinner > empty; handle error state
- **Form validation**: Show errors on blur or submit; don't block typing
- **List virtualization**: Use when >100 items; set item height for scroll
## Related
- Use `@component-creation` skill for new components
- See `@accessibility` for a11y requirements
Discussion
Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.
Posts are public.Sign in to post
No one has posted yet. Be the first.

