| name | component-architecture |
| description | Defines naming conventions, file structure, prop patterns, and composition rules for React/Next.js components. Ensures consistency across the codebase.
|
| version | 1 |
| author | Motion_Viz |
| tags | ["react","nextjs","components","architecture"] |
Component Architecture
Purpose
Enforce consistent component structure, naming, and file organization.
INPUT: Any component or page build request.
OUTPUT: Components that follow these conventions exactly.
When to Use This Skill
- Every React/Next.js component creation
- Every page build
- Any refactoring or code review
Rules (Non-Negotiable)
- PascalCase for components: HeroSection, PricingCard
- camelCase for utilities and hooks: useScrollPosition, formatDate
- One component per file (no multi-component exports)
- Props interface defined at TOP of file, before component
- Default exports only (no named exports for components)
- No inline styles (use Tailwind classes exclusively)
- All text content passed as props (never hardcode strings)
- Destructure props in function signature
- TypeScript for all files (.tsx, not .jsx)
File Structure
src/
โโโ components/
โ โโโ ui/ Reusable primitives
โ โ โโโ Button.tsx
โ โ โโโ Card.tsx
โ โ โโโ Badge.tsx
โ โ โโโ Input.tsx
โ โ โโโ Modal.tsx
โ โโโ sections/ Page-level sections
โ โ โโโ HeroSection.tsx
โ โ โโโ PricingSection.tsx
โ โ โโโ FAQSection.tsx
โ โ โโโ TestimonialSection.tsx
โ โ โโโ CTASection.tsx
โ โโโ layout/ Structural wrappers
โ โโโ Header.tsx
โ โโโ Footer.tsx
โ โโโ Sidebar.tsx
โ โโโ Container.tsx
โโโ hooks/ Custom React hooks
โ โโโ useMediaQuery.ts
โ โโโ useIntersection.ts
โ โโโ useScrollPosition.ts
โโโ lib/ Utilities & constants
โ โโโ utils.ts
โ โโโ constants.ts
โ โโโ types.ts
โโโ app/ Next.js App Router pages
โโโ page.tsx
โโโ layout.tsx
โโโ [slug]/
โโโ page.tsx
Component Template
interface [ComponentName]Props {
title: string;
description: string;
variant?: 'primary' | 'secondary';
className?: string;
}
export default function [ComponentName]({
title,
description,
variant = 'primary',
className = '',
}: [ComponentName]Props) {
return (
<section className={`[base-classes] ${className}`}>
<h2>{title}</h2>
<p>{description}</p>
</section>
);
}
Naming Conventions
Components
Sections: [Name]Section โ HeroSection, PricingSection
Cards: [Name]Card โ TestimonialCard, FeatureCard
Lists: [Name]List โ FeatureList, TeamList
Items: [Name]Item โ NavItem, FAQItem
Buttons: Button โ with variant prop
Inputs: [Name]Input โ SearchInput, EmailInput
Modals: [Name]Modal โ ContactModal, VideoModal
Badges: Badge โ with variant prop
Hooks
Hooks: use[Action/State] โ useMediaQuery, useScrollPosition
Utilities
Formatters: format[Thing] โ formatDate, formatCurrency
Validators: validate[Thing] โ validateEmail, validatePhone
Helpers: [verb][Thing] โ generateId, parseMarkdown
Constants: UPPER_SNAKE_CASE โ MAX_ITEMS, API_BASE_URL
Types: PascalCase โ ButtonVariant, CardProps
Composition Rules
- Sections compose UI components (never the reverse)
- UI components are stateless when possible
- Layout components only handle positioning/structure
- Data fetching happens in page.tsx or server components
- Client-side state lives in the component that needs it
- Shared state goes in a hook, not Context (unless truly global)
Prop Patterns
Boolean Props
isLoading?: boolean;
isVisible?: boolean;
hasIcon?: boolean;
isNotLoading?: boolean;
isHidden?: boolean;
Event Props
onClick?: () => void;
onSubmit?: (data: FormData) => void;
onChange?: (value: string) => void;
Children Pattern
interface ContainerProps {
children: React.ReactNode;
maxWidth?: 'sm' | 'md' | 'lg' | 'xl';
}
Anti-Patterns (Never Do This)
export function Header() { ... }
export function Footer() { ... }
<h1>Welcome to Our Platform</h1>
<div style={{ padding: '16px', color: 'red' }}>
// BAD: Named exports for components
export const HeroSection = () => { ... }
// BAD: No props interface
export default function Card(props: any) { ... }
// BAD: Logic in JSX
<div>{items.filter(i => i.active).map(i => <span>{i.name}</span>)}</div>
// GOOD: Extract logic
const activeItems = items.filter(i => i.active);
return <div>{activeItems.map(i => <span>{i.name}</span>)}</div>
Checklist (AI Self-Verification)