Skip to main content

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