ogt-docs-rules-code-front
OGT Docs - Rules Code Front
Frontend-specific coding standards for React/TypeScript applications.
Overview
Frontend rules establish consistent patterns for React components, state management, styling, and client-side architecture.
flowchart TB
subgraph front ["docs/rules/code/front/"]
COMP["components/"]
STATE["state/"]
HOOKS["hooks/"]
STYLE["styling/"]
ROUTE["routing/"]
FETCH["data_fetching/"]
end
COMP --> |patterns| C1["composition"]
COMP --> |patterns| C2["props"]
STATE --> |patterns| S1["context"]
STATE --> |patterns| S2["local"]
HOOKS --> |patterns| H1["custom"]
STYLE --> |patterns| ST1["css-in-js"]
When to Use
- Creating React component standards
- Defining state management patterns
- Establishing styling conventions
- Writing custom hook guidelines
- Setting data fetching patterns
- Defining routing conventions
Folder Structure
docs/rules/code/front/
├── components/ # Component patterns
│ ├── composition/
│ │ ├── rule.md
│ │ └── examples.md
│ ├── props/
│ │ ├── rule.md
│ │ └── examples.md
│ ├── naming/
│ │ ├── rule.md
│ │ └── examples.md
│ └── file_structure/
│ ├── rule.md
│ └── examples.md
│
├── state/ # State management
│ ├── local_state/
│ │ ├── rule.md
│ │ └── examples.md
│ ├── context/
│ │ ├── rule.md
│ │ └── examples.md
│ └── derived_state/
│ ├── rule.md
│ └── examples.md
│
├── hooks/ # Custom hooks
│ ├── naming/
│ │ ├── rule.md
│ │ └── examples.md
│ ├── dependencies/
│ │ ├── rule.md
│ │ └── examples.md
│ └── patterns/
│ ├── rule.md
│ └── examples.md
│
├── styling/ # CSS/Styling
│ ├── approach/
│ │ ├── rule.md
│ │ └── examples.md
│ ├── naming/
│ │ ├── rule.md
│ │ └── examples.md
│ └── responsive/
│ ├── rule.md
│ └── examples.md
│
├── data_fetching/ # Data fetching
│ ├── patterns/
│ │ ├── rule.md
│ │ └── examples.md
│ └── error_handling/
│ ├── rule.md
│ └── examples.md
│
└── routing/ # Routing
├── structure/
│ ├── rule.md
│ └── examples.md
└── navigation/
├── rule.md
└── examples.md
Example: docs/rules/code/front/components/composition/
Component composition patterns.
rule.md
# Rule: Component Composition
## Summary
Components MUST use composition over prop drilling for flexible, reusable designs.
## Rationale
Composition patterns:
- Reduce prop drilling
- Increase reusability
- Improve testability
- Enable flexible layouts
## The Rules
### 1. Prefer Children Over Props
**SHOULD** pass content via children rather than render props.
```tsx
// PREFERRED
<Card>
<CardHeader>Title</CardHeader>
<CardBody>Content</CardBody>
</Card>
// AVOID
<Card
header={<span>Title</span>}
body={<span>Content</span>}
/>
```
2. Use Compound Components
SHOULD use compound component pattern for related components.
// CORRECT - compound components
<Select>
<Select.Option value="a">Option A</Select.Option>
<Select.Option value="b">Option B</Select.Option>
</Select>
// AVOID - array of objects
<Select options={[
{ value: 'a', label: 'Option A' },
{ value: 'b', label: 'Option B' },
]} />
3. Avoid Prop Drilling
MUST NOT pass props more than 2 levels deep. Use context or composition.
// BAD - prop drilling
<App user={user}>
<Layout user={user}>
<Header user={user}>
<UserMenu user={user} /> // 4 levels!
</Header>
</Layout>
</App>
// GOOD - context
<UserProvider user={user}>
<App>
<Layout>
<Header>
<UserMenu /> // Uses useUser()
</Header>
</Layout>
</App>
</UserProvider>
4. Single Responsibility
Each component MUST have one clear purpose.
- Display components: render UI
- Container components: manage state/data
- Layout components: arrange children
Examples
Correct: Flexible Card Component
// Compound component pattern
const Card = ({ children, className }: CardProps) => (
<div className={cn("card", className)}>{children}</div>
);
Card.Header = ({ children }: { children: ReactNode }) => (
<div className="card-header">{children}</div>
);
Card.Body = ({ children }: { children: ReactNode }) => (
<div className="card-body">{children}</div>
);
Card.Footer = ({ children }: { children: ReactNode }) => (
<div className="card-footer">{children}</div>
);
// Usage - flexible composition
<Card>
<Card.Header>
<h2>Title</h2>
<IconButton icon="close" />
</Card.Header>
<Card.Body>
<p>Any content here</p>
</Card.Body>
</Card>;
Incorrect: Inflexible Props-Based
// BAD - limited flexibility
interface CardProps {
title: string;
subtitle?: string;
body: string;
footer?: string;
showCloseButton?: boolean;
onClose?: () => void;
headerIcon?: ReactNode;
// Props multiply as requirements grow...
}
const Card = ({ title, subtitle, body, ... }: CardProps) => (
// Complex conditional rendering
);
Enforcement
- Code review checklist
- ESLint custom rules for prop drilling detection
---
## Example: docs/rules/code/front/state/local_state/
Local state management rules.
### rule.md
```markdown
# Rule: Local State Management
## Summary
Component state MUST be kept as local as possible and lifted only when necessary.
## Rationale
Local state:
- Improves performance (fewer re-renders)
- Reduces complexity
- Makes components self-contained
- Easier to test
## The Rules
### 1. Start Local
**MUST** start with local state and lift only when needed.
```tsx
// START HERE - local state
const [count, setCount] = useState(0);
// LIFT when siblings need it
// LIFT when parent needs it
// LIFT when distant components need it
2. Colocation
MUST keep state close to where it's used.
// CORRECT - state in component that uses it
function SearchInput() {
const [query, setQuery] = useState("");
return <input value={query} onChange={(e) => setQuery(e.target.value)} />;
}
// INCORRECT - state lifted unnecessarily
function App() {
const [searchQuery, setSearchQuery] = useState("");
return <SearchInput query={searchQuery} setQuery={setSearchQuery} />;
}
3. Derive Don't Duplicate
MUST derive state from existing state rather than duplicating.
// CORRECT - derived
const [items, setItems] = useState<Item[]>([]);
const completedCount = items.filter((i) => i.completed).length;
// INCORRECT - duplicated state
const [items, setItems] = useState<Item[]>([]);
const [completedCount, setCompletedCount] = useState(0);
// Now you have to keep them in sync!
4. Use Appropriate Hook
| Scenario | Hook |
|---|---|
| Simple value | useState |
| Complex object with many updates | useReducer |
| Previous value needed | useRef + useState |
| Derived async data | useMemo or data fetching library |
Examples
Correct: Appropriate State Location
// Form with local state
function ContactForm() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [message, setMessage] = useState("");
// Derived state
const isValid = name.length > 0 && email.includes("@");
return (
<form>
<input value={name} onChange={(e) => setName(e.target.value)} />
<input value={email} onChange={(e) => setEmail(e.target.value)} />
<textarea value={message} onChange={(e) => setMessage(e.target.value)} />
<button disabled={!isValid}>Submit</button>
</form>
);
}
Correct: useReducer for Complex State
type State = {
items: Item[];
filter: "all" | "active" | "completed";
editingId: string | null;
};
type Action =
| { type: "ADD_ITEM"; payload: Item }
| { type: "TOGGLE_ITEM"; payload: string }
| { type: "SET_FILTER"; payload: State["filter"] }
| { type: "START_EDITING"; payload: string };
function reducer(state: State, action: Action): State {
switch (action.type) {
case "ADD_ITEM":
return { ...state, items: [...state.items, action.payload] };
// ... other cases
}
}
function TodoList() {
const [state, dispatch] = useReducer(reducer, initialState);
// ...
}
Enforcement
- Code review
- ESLint react-hooks/exhaustive-deps
---
## Example: docs/rules/code/front/hooks/naming/
Custom hook naming rules.
### rule.md
```markdown
# Rule: Custom Hook Naming
## Summary
Custom hooks MUST be named with `use` prefix and describe their purpose.
## Rationale
Consistent naming:
- Enables React's hooks linting
- Communicates purpose clearly
- Follows React conventions
- Makes hooks discoverable
## The Rules
### 1. Use Prefix Required
**MUST** start with `use` followed by PascalCase description.
```typescript
// CORRECT
useUserData
useLocalStorage
useDebounce
useCreatureList
// INCORRECT
getUserData // Not a hook name
UseUserData // Wrong case
use_user_data // Wrong format
2. Describe the Data or Action
SHOULD name after what it returns or does.
| Hook Returns | Name Pattern |
|---|---|
| User data | useUser, useCurrentUser |
| List of items | useItems, useCreatures |
| Boolean state | useIsOpen, useIsLoading |
| Toggle function | useToggle, useDisclosure |
| Async operation | useFetch, useQuery |
3. File Naming
MUST match file name to hook name in kebab-case.
hooks/
use-user-data.ts -> export function useUserData()
use-local-storage.ts -> export function useLocalStorage()
use-debounce.ts -> export function useDebounce()
Examples
Correct
// use-creature-data.ts
export function useCreatureData(slug: string) {
const [creature, setCreature] = useState<Creature | null>(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
fetchCreature(slug)
.then(setCreature)
.finally(() => setIsLoading(false));
}, [slug]);
return { creature, isLoading };
}
// use-toggle.ts
export function useToggle(initial = false) {
const [value, setValue] = useState(initial);
const toggle = useCallback(() => setValue((v) => !v), []);
const setTrue = useCallback(() => setValue(true), []);
const setFalse = useCallback(() => setValue(false), []);
return { value, toggle, setTrue, setFalse };
}
Incorrect
// BAD - not descriptive
export function useData() { ... }
// BAD - wrong prefix
export function fetchUserData() { ... } // Looks like regular function
// BAD - file mismatch
// File: userData.ts
export function useUserData() { ... } // Should be use-user-data.ts
Enforcement
- ESLint react-hooks/rules-of-hooks
- File naming linter
---
## Example: docs/rules/code/front/styling/approach/
Styling approach rules.
### rule.md
```markdown
# Rule: Styling Approach
## Summary
Projects MUST use a consistent styling approach and SHOULD prefer CSS-in-JS or utility classes.
## Rationale
Consistent styling:
- Reduces context switching
- Enables type-safe styles
- Improves maintainability
- Colocates styles with components
## The Rules
### 1. Choose One Approach
**MUST** use one primary styling approach per project:
| Approach | When to Use |
|----------|-------------|
| Tailwind CSS | Utility-first, rapid development |
| CSS Modules | Scoped CSS, traditional CSS knowledge |
| styled-components | Component-based, dynamic styles |
| Vanilla Extract | Type-safe, zero runtime |
### 2. Consistent Application
**MUST** apply chosen approach consistently across all components.
### 3. Component-Scoped Styles
**MUST NOT** use global styles except for:
- CSS reset/normalize
- CSS variables (design tokens)
- Base typography
### 4. Design Tokens
**SHOULD** use design tokens for colors, spacing, typography.
```tsx
// CORRECT - using tokens
<div className="p-4 bg-primary text-white" />
<div style={{ padding: tokens.spacing.md }} />
// INCORRECT - magic values
<div style={{ padding: '16px', backgroundColor: '#3b82f6' }} />
Examples
Tailwind CSS Approach
// Component with Tailwind
function Card({ title, children }: CardProps) {
return (
<div className="rounded-lg border border-gray-200 bg-white p-4 shadow-sm">
<h2 className="mb-2 text-lg font-semibold text-gray-900">{title}</h2>
<div className="text-gray-600">{children}</div>
</div>
);
}
// With cn() for conditional classes
function Button({ variant, children }: ButtonProps) {
return (
<button
className={cn(
"rounded px-4 py-2 font-medium transition-colors",
variant === "primary" && "bg-blue-500 text-white hover:bg-blue-600",
variant === "secondary" &&
"bg-gray-200 text-gray-900 hover:bg-gray-300",
)}
>
{children}
</button>
);
}
CSS Modules Approach
// Card.module.css
.card {
border-radius: var(--radius-lg);
border: 1px solid var(--color-border);
padding: var(--spacing-md);
}
.title {
font-size: var(--font-size-lg);
font-weight: var(--font-weight-semibold);
}
// Card.tsx
import styles from './Card.module.css';
function Card({ title, children }: CardProps) {
return (
<div className={styles.card}>
<h2 className={styles.title}>{title}</h2>
{children}
</div>
);
}
Enforcement
- ESLint Tailwind plugin (if using Tailwind)
- Code review
---
## Creating Frontend Rules
```mermaid
flowchart TD
A[Identify Pattern] --> B{Category}
B -->|Components| C[components/]
B -->|State| D[state/]
B -->|Hooks| E[hooks/]
B -->|Styling| F[styling/]
B -->|Data| G[data_fetching/]
B -->|Routes| H[routing/]
C --> I[Create Rule Folder]
D --> I
E --> I
F --> I
G --> I
H --> I
I --> J[Write rule.md]
J --> K[Add examples.md]
K --> L[Configure ESLint if applicable]
L --> M[Add to review checklist]
Signal Files Reference
| Signal | Content | Purpose |
|---|---|---|
.version |
JSON | Schema version |
.enforced_by |
List | Tools that enforce |
.eslint_rule |
Rule name | ESLint rule if applicable |
.react_version |
Version | React version requirement |
Frontend Rule Checklist
- Rule is React/frontend specific
- Examples use TypeScript + React
- Shows correct and incorrect patterns
- Mentions relevant ESLint rules
- Considers React best practices
- References React documentation if applicable
- Performance implications noted
More from opendndapps/ogt-skills
ogt-docs-changelog
Manage project changelog following Keep a Changelog format. Use when documenting releases, adding change entries, generating changelogs from commits, or maintaining version history.
10ogt-docs-define-tools
Document project tools and CLI utilities in docs/define/tools/. Use when documenting internal CLIs, scripts, development tools, or third-party integrations that team members need to understand and use.
9ogt-cli-claude
Run Claude Code CLI for complex tasks, code generation, analysis, and research. Uses Anthropic OAuth (included in Claude Pro). Use for extended thinking, code review, architecture decisions. Preferred for load balancing sub-agent work (35% weight).
8jq
Command-line JSON processor. Extract, filter, transform JSON.
8ogt-docs-define-branding
Create brand definition documents covering visual identity, tone of voice, brand guidelines, and brand assets. Use when establishing or documenting brand identity and ensuring consistent brand expression.
8ogt-agent-team
Spawn a Team Leader agent that manages multiple sub-agents working toward a common goal. Team Leader reads requirements, decomposes work, assigns personalities and tasks, manages communication between team members, tracks progress, and reports results following ogt-docs task workflow. Integrates fully with docs-first system via task signals and status tracking.
8