skills/opendndapps/ogt-skills/ogt-docs-rules-code-front

ogt-docs-rules-code-front

SKILL.md

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
Weekly Installs
6
First Seen
Feb 7, 2026
Installed on
openclaw6
antigravity6
claude-code6
github-copilot6
codex6
kimi-cli6