Frontend Development Guidelines (Next.js + Tailwind)
Purpose
Comprehensive guide for modern Next.js development with React, emphasizing Suspense-based data fetching, lazy loading, proper file organization, Tailwind CSS styling, and performance optimization.
When to Use This Skill
- •Creating new components or pages
- •Building new features
- •Fetching data from APIs
- •Setting up routing with Next.js App Router
- •Styling components with Tailwind CSS
- •Performance optimization
- •Organizing frontend code
- •TypeScript best practices
Quick Start
New Component Checklist
Creating a component? Follow this checklist:
- • Use proper TypeScript types for props
- • Use
'use client'directive if component uses hooks (Next.js) - • Use
dynamic()import for heavy components:dynamic(() => import()) - • Wrap in
<Suspense>for loading states - • Use
fetch()or external libraries for data fetching - • Style with Tailwind CSS classes
- • Use
useCallbackfor event handlers passed to children - • Default export at bottom
- • No early returns with loading spinners
- • Use proper error boundaries for error handling
New Feature Checklist
Creating a feature? Set up this structure in the app/ directory:
- • Create feature directory:
app/{feature-name}/ - • Create subdirectories:
components/,hooks/,api/,lib/,types/ - • Create page file:
app/{feature-name}/page.tsx - • Create layout if needed:
app/{feature-name}/layout.tsx - • Set up TypeScript types in
types/ - • Create API routes in
app/api/{feature}/if needed - • Lazy load heavy feature components with
dynamic() - • Use Suspense boundaries for async operations
- • Export utilities from feature
lib/directory
Import Aliases Quick Reference
ChoreQuest uses standard Next.js paths (no custom aliases currently). Use paths relative to app/:
// From components within app/
import { ComponentName } from '@/components/component-name'
import { useSomeHook } from '@/hooks/use-some-hook'
import type { TypeName } from '@/types/type-name'
// From API routes
import { someUtil } from '@/lib/utils'
Defined in: jsconfig.json or tsconfig.json
Common Imports Cheatsheet
// React & Next.js
import React, { useState, useCallback, useMemo, Suspense } from 'react';
import dynamic from 'next/dynamic';
import { useRouter } from 'next/navigation';
// Tailwind & UI
import clsx from 'clsx';
import { Lucide icons } from 'lucide-react'; // e.g., Check, X, AlertCircle
// Async & Data Fetching
import { headers } from 'next/headers';
// Project Utilities
import { cn } from '@/lib/utils';
// Custom Hooks
import { useAuth } from '@/hooks/useAuth';
import { useSomeHook } from '@/hooks/use-some-hook';
// Types
import type { User } from '@/types/user';
import type { Database } from '@/types/database';
Topic Guides
🎨 Component Patterns
Modern React components use:
- •
React.FC<Props>for type safety - •
React.lazy()for code splitting - •
SuspenseLoaderfor 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
isLoadingchecks - •Type-safe with generics
API Service Layer:
- •Create
features/{feature}/api/{feature}Api.ts - •Use
apiClientaxios 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.tsfile
Primary Method:
- •Use
sxprop for MUI components - •Type-safe with
SxProps<Theme> - •Theme access:
(theme) => theme.palette.primary.main
MUI v7 Grid:
<Grid size={{ xs: 12, md: 6 }}> // ✅ v7 syntax
<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:
import { createFileRoute } from '@tanstack/react-router';
import { lazy } from 'react';
const MyPage = lazy(() => import('@/features/my-feature/components/MyPage'));
export const Route = createFileRoute('/my-route/')({
component: MyPage,
loader: () => ({ crumb: 'My Route' }),
});
📖 Complete Guide: resources/routing-guide.md
⏳ Loading & Error States
CRITICAL RULE: No Early Returns
// ❌ NEVER - Causes layout shift
if (isLoading) {
return <LoadingSpinner />;
}
// ✅ ALWAYS - Consistent layout
<SuspenseLoader>
<Content />
</SuspenseLoader>
Why: Prevents Cumulative Layout Shift (CLS), better UX
Error Handling:
- •Use
useMuiSnackbarfor user feedback - •NEVER
react-toastify - •TanStack Query
onErrorcallbacks
📖 Complete Guide: resources/loading-and-error-states.md
⚡ Performance
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
anytype - •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
- •
useAuthhook for current user - •Mutation patterns with cache invalidation
📖 Complete Guide: resources/common-patterns.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
| Need to... | Read this resource |
|---|---|
| Create a component | component-patterns.md |
| Fetch data | data-fetching.md |
| Organize files/folders | file-organization.md |
| Style components | styling-guide.md |
| Set up routing | routing-guide.md |
| Handle loading/errors | loading-and-error-states.md |
| Optimize performance | performance.md |
| TypeScript types | typescript-standards.md |
| Forms/Auth/DataGrid | common-patterns.md |
| See full examples | complete-examples.md |
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)
import React, { useState, useCallback } from 'react';
import { Box, Paper } from '@mui/material';
import { useSuspenseQuery } from '@tanstack/react-query';
import { featureApi } from '../api/featureApi';
import type { FeatureData } from '~types/feature';
interface MyComponentProps {
id: number;
onAction?: () => void;
}
export const MyComponent: React.FC<MyComponentProps> = ({ id, onAction }) => {
const [state, setState] = useState<string>('');
const { data } = useSuspenseQuery({
queryKey: ['feature', id],
queryFn: () => featureApi.getFeature(id),
});
const handleAction = useCallback(() => {
setState('updated');
onAction?.();
}, [onAction]);
return (
<Box sx={{ p: 2 }}>
<Paper sx={{ p: 3 }}>
{/* Content */}
</Paper>
</Box>
);
};
export default MyComponent;
For complete examples, see resources/complete-examples.md
Related Skills
- •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