Frontend Development Guidelines
Purpose
Comprehensive guide for modern React development, emphasizing Suspense-based data fetching, lazy loading, proper file organization, and performance optimization.
When to Use This Skill
- Creating new components or pages
- Building new features
- Fetching data with TanStack Query
- Setting up routing with TanStack Router
- Styling components with MUI v7
- Performance optimization
- Organizing frontend code
- TypeScript best practices
Quick Start
New Component Checklist
Creating a component? Follow this checklist:
New Feature Checklist
Creating a feature? Set up this structure:
Import Aliases Quick Reference
| Alias | Resolves To | Example |
|---|
@/ | src/ | import { apiClient } from '@/lib/apiClient' |
~types | src/types | import type { User } from '~types/user' |
~components | src/components | import { SuspenseLoader } from '~components/SuspenseLoader' |
~features | src/features | import { authApi } from '~features/auth' |
Defined in: vite.config.ts lines 180-185
Common Imports Cheatsheet
typescript
1// React & Lazy Loading
2import React, { useState, useCallback, useMemo } from 'react';
3const Heavy = React.lazy(() => import('./Heavy'));
4
5// MUI Components
6import { Box, Paper, Typography, Button, Grid } from '@mui/material';
7import type { SxProps, Theme } from '@mui/material';
8
9// TanStack Query (Suspense)
10import { useSuspenseQuery, useQueryClient } from '@tanstack/react-query';
11
12// TanStack Router
13import { createFileRoute } from '@tanstack/react-router';
14
15// Project Components
16import { SuspenseLoader } from '~components/SuspenseLoader';
17
18// Hooks
19import { useAuth } from '@/hooks/useAuth';
20import { useMuiSnackbar } from '@/hooks/useMuiSnackbar';
21
22// Types
23import type { Post } from '~types/post';
Topic Guides
🎨 Component Patterns
Modern React components use:
React.FC<Props> for type safety
React.lazy() for code splitting
SuspenseLoader for loading states
- Named const + default export pattern
Key Concepts:
- Lazy load heavy components (DataGrid, charts, editors)
- Always wrap lazy components in Suspense
- Use SuspenseLoader component (with fade animation)
- Component structure: Props → Hooks → Handlers → Render → Export
📖 Complete Guide: resources/component-patterns.md
📊 Data Fetching
PRIMARY PATTERN: useSuspenseQuery
- Use with Suspense boundaries
- Cache-first strategy (check grid cache before API)
- Replaces
isLoading checks
- Type-safe with generics
API Service Layer:
- Create
features/{feature}/api/{feature}Api.ts
- Use
apiClient axios instance
- Centralized methods per feature
- Route format:
/form/route (NOT /api/form/route)
📖 Complete Guide: resources/data-fetching.md
📁 File Organization
features/ vs components/:
features/: Domain-specific (posts, comments, auth)
components/: Truly reusable (SuspenseLoader, CustomAppBar)
Feature Subdirectories:
features/
my-feature/
api/ # API service layer
components/ # Feature components
hooks/ # Custom hooks
helpers/ # Utility functions
types/ # TypeScript types
📖 Complete Guide: resources/file-organization.md
🎨 Styling
Inline vs Separate:
- <100 lines: Inline
const styles: Record<string, SxProps<Theme>>
-
100 lines: Separate .styles.ts file
Primary Method:
- Use
sx prop for MUI components
- Type-safe with
SxProps<Theme>
- Theme access:
(theme) => theme.palette.primary.main
MUI v7 Grid:
typescript
1<Grid size={{ xs: 12, md: 6 }}> // ✅ v7 syntax
2<Grid xs={12} md={6}> // ❌ Old syntax
📖 Complete Guide: resources/styling-guide.md
🛣️ Routing
TanStack Router - Folder-Based:
- Directory:
routes/my-route/index.tsx
- Lazy load components
- Use
createFileRoute
- Breadcrumb data in loader
Example:
typescript
1import { createFileRoute } from '@tanstack/react-router';
2import { lazy } from 'react';
3
4const MyPage = lazy(() => import('@/features/my-feature/components/MyPage'));
5
6export const Route = createFileRoute('/my-route/')({
7 component: MyPage,
8 loader: () => ({ crumb: 'My Route' }),
9});
📖 Complete Guide: resources/routing-guide.md
⏳ Loading & Error States
CRITICAL RULE: No Early Returns
typescript
1// ❌ NEVER - Causes layout shift
2if (isLoading) {
3 return <LoadingSpinner />;
4}
5
6// ✅ ALWAYS - Consistent layout
7<SuspenseLoader>
8 <Content />
9</SuspenseLoader>
Why: Prevents Cumulative Layout Shift (CLS), better UX
Error Handling:
- Use
useMuiSnackbar for user feedback
- NEVER
react-toastify
- TanStack Query
onError callbacks
📖 Complete Guide: resources/loading-and-error-states.md
Optimization Patterns:
useMemo: Expensive computations (filter, sort, map)
useCallback: Event handlers passed to children
React.memo: Expensive components
- Debounced search (300-500ms)
- Memory leak prevention (cleanup in useEffect)
📖 Complete Guide: resources/performance.md
📘 TypeScript
Standards:
- Strict mode, no
any type
- Explicit return types on functions
- Type imports:
import type { User } from '~types/user'
- Component prop interfaces with JSDoc
📖 Complete Guide: resources/typescript-standards.md
🔧 Common Patterns
Covered Topics:
- React Hook Form with Zod validation
- DataGrid wrapper contracts
- Dialog component standards
useAuth hook for current user
- Mutation patterns with cache invalidation
📖 Complete Guide: resources/common-patterns.md
👤 User Avatars
ALWAYS use AvatarUrl helper for user avatars - handles empty strings, Discord IDs, and fallback generation.
typescript
1import { AvatarUrl } from "~/components/user/avatar";
2<img src={AvatarUrl(user)} />
📖 Complete Guide: resources/user-avatar.md
📚 Complete Examples
Full working examples:
- Modern component with all patterns
- Complete feature structure
- API service layer
- Route with lazy loading
- Suspense + useSuspenseQuery
- Form with validation
📖 Complete Guide: resources/complete-examples.md
Navigation Guide
Core Principles
- Lazy Load Everything Heavy: Routes, DataGrid, charts, editors
- Suspense for Loading: Use SuspenseLoader, not early returns
- useSuspenseQuery: Primary data fetching pattern for new code
- Features are Organized: api/, components/, hooks/, helpers/ subdirs
- Styles Based on Size: <100 inline, >100 separate
- Import Aliases: Use @/, ~types, ~components, ~features
- No Early Returns: Prevents layout shift
- useMuiSnackbar: For all user notifications
Quick Reference: File Structure
src/
features/
my-feature/
api/
myFeatureApi.ts # API service
components/
MyFeature.tsx # Main component
SubComponent.tsx # Related components
hooks/
useMyFeature.ts # Custom hooks
useSuspenseMyFeature.ts # Suspense hooks
helpers/
myFeatureHelpers.ts # Utilities
types/
index.ts # TypeScript types
index.ts # Public exports
components/
SuspenseLoader/
SuspenseLoader.tsx # Reusable loader
CustomAppBar/
CustomAppBar.tsx # Reusable app bar
routes/
my-route/
index.tsx # Route component
create/
index.tsx # Nested route
Modern Component Template (Quick Copy)
typescript
1import React, { useState, useCallback } from 'react';
2import { Box, Paper } from '@mui/material';
3import { useSuspenseQuery } from '@tanstack/react-query';
4import { featureApi } from '../api/featureApi';
5import type { FeatureData } from '~types/feature';
6
7interface MyComponentProps {
8 id: number;
9 onAction?: () => void;
10}
11
12export const MyComponent: React.FC<MyComponentProps> = ({ id, onAction }) => {
13 const [state, setState] = useState<string>('');
14
15 const { data } = useSuspenseQuery({
16 queryKey: ['feature', id],
17 queryFn: () => featureApi.getFeature(id),
18 });
19
20 const handleAction = useCallback(() => {
21 setState('updated');
22 onAction?.();
23 }, [onAction]);
24
25 return (
26 <Box sx={{ p: 2 }}>
27 <Paper sx={{ p: 3 }}>
28 {/* Content */}
29 </Paper>
30 </Box>
31 );
32};
33
34export default MyComponent;
For complete examples, see resources/complete-examples.md
- error-tracking: Error tracking with Sentry (applies to frontend too)
- backend-dev-guidelines: Backend API patterns that frontend consumes
Skill Status: Modular structure with progressive loading for optimal context management