AI Rule Prompt
Prompt
If you want to enhance your AI agent with this pattern, you can use the following prompt as a rule prompt or skill. Use the copy button (top right) to copy the prompt and paste it into your AI agent.
# React Nesting File Pattern
## Overview
When creating and composing React components in this project, you **must** use the React Nesting File Pattern. This pattern aligns with React's fundamental principle: "Understand your UI as a tree of components."
This project uses the [File Nesting Explorer](https://explorer.groverlee.me/) extension to visualize and manage nested component structures effectively.
## Core Principles
1. **No Monolithic Components**: Never create single files containing all logic, markup, and state management
2. **Tree Structure**: Organize components in a hierarchical tree that mirrors the UI structure
3. **Separation of Concerns**: Each component should have a single, focused responsibility
4. **Self-Contained Logic**: Components must implement their own logic and not depend on siblings
5. **Atomic Design**: Apply atomic design principles for composability and maintainability
## File Structure Convention
Use the `@` prefix to indicate nested component directories:
```
ComponentName.tsx
@ComponentName/
├── ChildComponent.tsx
├── AnotherChild.tsx
└── @AnotherChild/
└── GrandchildComponent.tsx
```
## Practical Example
### ❌ **AVOID**: Single File Approach
```tsx
export const MyComponent = () => {
const myContext1 = useContext(MyContext1);
const myContext2 = useContext(MyContext2);
const handleCreate = () => {
// uses myContext1
};
const handleDelete = () => {
// uses myContext2
};
return (
<div>
{/* Header */}
<div>
<h1>My Component</h1>
<div>....</div>
</div>
{/* Content */}
<div>
<p>My Component Content</p>
{/* uses myContext2 */}
</div>
{/* Action bar */}
<div>
<button onClick={handleCreate}>Create</button>
<button onClick={handleDelete}>Delete</button>
</div>
</div>
);
};
```
### ✅ **CORRECT**: Nested File Approach
#### File Structure
```
MyComponent.tsx
@MyComponent/
├── Header.tsx
├── Content.tsx
├── ActionBar.tsx
└── @ActionBar/
├── CreateButton.tsx
└── DeleteButton.tsx
```
#### `MyComponent.tsx`
```tsx
import { Header } from "./@MyComponent/Header";
import { Content } from "./@MyComponent/Content";
import { ActionBar } from "./@MyComponent/ActionBar";
export const MyComponent = () => {
return (
<div>
<Header />
<Content />
<ActionBar />
</div>
);
};
```
#### `@MyComponent/Header.tsx`
```tsx
export const Header = () => (
<div>
<h1>My Component</h1>
<div>....</div>
</div>
);
```
#### `@MyComponent/Content.tsx`
```tsx
export const Content = () => {
const myContext2 = useContext(MyContext2);
return (
<div>
<p>My Component Content</p>
{/* uses myContext2 */}
</div>
);
};
```
#### `@MyComponent/ActionBar.tsx`
```tsx
import { CreateButton } from "./@ActionBar/CreateButton";
import { DeleteButton } from "./@ActionBar/DeleteButton";
export const ActionBar = () => {
return (
<div>
<p>Action Content</p>
<CreateButton />
<DeleteButton />
</div>
);
};
```
#### `@MyComponent/@ActionBar/CreateButton.tsx`
```tsx
export const CreateButton = () => {
const myContext1 = useContext(MyContext1);
const handleCreate = () => {
// uses myContext1
};
return <button onClick={handleCreate}>Create</button>;
};
```
#### `@MyComponent/@ActionBar/DeleteButton.tsx`
```tsx
export const DeleteButton = () => {
const myContext2 = useContext(MyContext2);
const handleDelete = () => {
// uses myContext2
};
return <button onClick={handleDelete}>Delete</button>;
};
```
## When to Split Components
Split components when:
- A component has multiple distinct UI sections (header, content, footer)
- Logic becomes complex and can be isolated
- State or context usage can be localized to child components
- A component exceeds ~100-150 lines
- Multiple event handlers serve different purposes
- Child components could potentially be reused
## When to Keep Components Together
Keep components in a single file when:
- The component is truly atomic (a button, input, or simple UI element)
- Splitting would create unnecessary complexity
- The component has less than ~50 lines with a single clear purpose
## Benefits
- **Better Code Organization**: Clear hierarchical structure
- **Improved Maintainability**: Easy to locate and update specific functionality
- **Enhanced Reusability**: Self-contained components are easier to reuse
- **Optimized Performance**: Easier to implement React.memo and optimization strategies
- **Team Collaboration**: Reduced merge conflicts and clearer ownership
- **Visual Clarity**: File Nesting Explorer provides an intuitive tree view
## Support Files and Component Folders
When a component has **support files** (styles, hooks, utilities, types) tied specifically to it, create a **folder** instead of a standalone component file and colocate all related files together.
### The Problem: Centralized Support Files
❌ **AVOID**: Keeping all support files at the parent level
```
styles.css // all styles mixed together
MyComponent.tsx
@MyComponent/
├── Header.tsx
├── Content.tsx
├── ActionBar.tsx
```
This creates:
- Difficult maintenance (finding which styles belong to which component)
- Tight coupling between parent and children
- Reduced reusability of child components
### The Solution: Colocated Support Files
✅ **CORRECT**: Move support files into component-specific folders
```
MyComponent.css // styles only for MyComponent itself
MyComponent.tsx
@MyComponent/
├── header/
│ ├── Header.tsx
│ ├── header.css
│ └── useHeaderState.ts
├── Content.tsx
└── ActionBar.tsx
```
### Support File Examples
#### Example 1: Component with Styles
```
@MyComponent/
└── header/
├── Header.tsx
└── header.css
```
#### Example 2: Component with Custom Hook
```
@MyComponent/
└── header/
├── Header.tsx
└── useHeaderData.ts
```
#### Example 3: Component with Multiple Support Files
```
@MyComponent/
└── header/
├── Header.tsx
├── header.css
├── useHeaderState.ts
├── useHeaderAnimation.ts
└── types.ts
```
#### Example 4: Nested Component with Support Files
```
@MyComponent/
└── action-bar/
├── ActionBar.tsx
├── action-bar.css
└── @action-bar/
└── create-button/
├── CreateButton.tsx
├── create-button.css
└── useCreateAction.ts
```
### Naming Conventions for Support Files
When creating component folders with support files:
1. **Folder names**: Use lowercase kebab-case (`header/`, `action-bar/`)
2. **Component files**: Use PascalCase (`Header.tsx`, `ActionBar.tsx`)
3. **Style files**: Match the folder or component name in kebab-case (`header.css`, `action-bar.css`)
4. **Hook files**: Use camelCase with `use` prefix (`useHeaderData.ts`, `useCreateAction.ts`)
5. **Type files**: Use lowercase (`types.ts`, `interfaces.ts`, `constants.ts`)
### When to Create Component Folders
✅ **Create a folder when**:
- Component has dedicated CSS/styles
- Component has one or more custom hooks
- Component has specific type definitions
- Component has utilities/helpers used only by it
- Component has test files
- Component has constants or configuration
❌ **Keep as single file when**:
- Component has no support files
- Component is purely presentational with no additional dependencies
- Component only imports from shared/common directories
### Import Path Examples
#### Importing Component from Folder
```tsx
// MyComponent.tsx
import { Header } from "./@MyComponent/header/Header";
import { Content } from "./@MyComponent/Content";
```
#### Using Colocated Support Files
```tsx
// @MyComponent/header/Header.tsx
import "./header.css";
import { useHeaderState } from "./useHeaderState";
export const Header = () => {
const state = useHeaderState();
return <div className="header">...</div>;
};
```
### Benefits of Colocated Support Files
- **Better Encapsulation**: All component-related code lives together
- **Improved Portability**: Easy to move/copy entire component with all dependencies
- **Clearer Ownership**: Obvious which styles/hooks belong to which component
- **Reduced Conflicts**: Team members can work on different components without collision
- **Enhanced Discoverability**: Related files are always in the same location
## Implementation Rules
1. **Always** create a `@ComponentName/` directory for nested children
2. **Import** child components using relative paths: `./@ComponentName/ChildComponent` or `./@ComponentName/component-name/ComponentName`
3. **Colocate** all component-specific support files (styles, hooks, types) within component folders
4. **Colocate** context usage with the component that needs it
5. **Avoid** prop drilling by using context at the appropriate level
6. **Name** components clearly to reflect their role in the UI hierarchy
7. **Use kebab-case** for component folder names and snake_case or kebab-case for support files
8. **Document** complex component trees with comments when necessary
## Component Ordering with `.sorting` Files
When a parent component uses its children in a **specific rendering order**, create a `.sorting` file inside the parent's folder to maintain that order in the File Nesting Explorer.
### Why Use `.sorting` Files?
By default, VSCode displays files alphabetically, which may not reflect the actual component usage order. The `.sorting` file allows the File Nesting Explorer to display children in the same sequence they appear in the JSX, improving code navigation and comprehension.
### Example
#### Parent Component: `MyComponent.tsx`
```tsx
import { Header } from "./@MyComponent/Header";
import { Content } from "./@MyComponent/Content";
import { ActionBar } from "./@MyComponent/ActionBar";
export const MyComponent = () => {
return (
<div>
<Header />
<Content />
<ActionBar />
</div>
);
};
```
#### Default VSCode Behavior (Alphabetical)
```
MyComponent.tsx
@MyComponent/
├── ActionBar.tsx
├── Content.tsx
├── Header.tsx
```
#### Create: `@MyComponent/.sorting`
```json
["Header.tsx", "Content.tsx", "ActionBar.tsx"]
```
#### Result: Custom Order in File Explorer
```
MyComponent.tsx
@MyComponent/
├── Header.tsx
├── Content.tsx
├── ActionBar.tsx
```
### Ordering Principles
The `.sorting` file should reflect either:
1. **Rendering Order**: The sequence components appear in JSX
2. **Data Flow Dependencies**: The order of dependencies from base to consumer
#### Data Flow Example: Hooks
When hooks depend on each other, list them in dependency order:
```json
["useBaseData.ts", "useProcessedData.ts", "Component.tsx"]
```
Where `useProcessedData` uses `useBaseData`, and `Component` uses `useProcessedData`.
#### Data Flow Example: Contexts
When contexts have dependencies, list from provider to consumer:
```json
["AuthContext.ts", "UserContext.ts", "Component.tsx"]
```
Where `UserContext` depends on `AuthContext`, and `Component` consumes `UserContext`.
#### Data Flow Example: Mixed Dependencies
```json
["useAuth.ts", "AuthContext.ts", "useUserData.ts", "UserProfile.tsx"]
```
This shows: `useAuth` → `AuthContext` → `useUserData` → `UserProfile`
### Rules for `.sorting` Files
1. **Create `.sorting` when order matters**: For rendering sequences, workflow steps, or dependency chains
2. **JSON array format**: List filenames exactly as they appear in the directory
3. **Follow dependency flow**: Order from foundational dependencies to consumers (bottom-up in the dependency tree)
4. **Match JSX order for components**: The array order should reflect the component rendering order
5. **Include all direct children**: All files **and folders** in the directory should be listed
6. **Mixed files and folders**: The sorting list can include both standalone files and component folders (e.g., `"Header.tsx"`, `"content/"`, `"ActionBar.tsx"`)
7. **Update when adding/removing**: Keep `.sorting` synchronized with file changes
8. **Nested directories**: Create separate `.sorting` files for each nested level if needed
### When to Create `.sorting` Files
✅ **Create when**:
- Components represent a visual flow (Header → Content → Footer)
- Order reflects user interaction sequence (Step1 → Step2 → Step3)
- Logical grouping matters (Navigation → Main → Sidebar)
- **Data dependencies exist** (hook1 → hook2 → component)
- **Context dependencies exist** (BaseContext → DerivedContext → Consumer)
- **Utility/helper dependencies exist** (validator → transformer → component)
❌ **Skip when**:
- Components are unordered collections (list items, grid cells)
- Alphabetical order is already meaningful
- Only 1-2 child files exist
- No clear rendering or dependency order exists
---
**Remember**: The goal is maintainability and clarity. Always ask: "Would splitting this component make the codebase easier to understand and maintain?" Use `.sorting` files to preserve meaningful component order in your file explorer.
Prompt CHANGELOG
- 2026-02-03: Initial release