REACT DEVELOPMENT STANDARDS - AI PROMPT
CRITICAL REQUIREMENTS - ERROR HANDLING, CHANGE LOGS, AND SIMPLICITY ARE MANDATORY
BROWSER STORAGE RESTRICTION: NEVER use localStorage, sessionStorage, or ANY browser storage APIs in React components. These APIs are NOT supported in Claude.ai artifacts and will cause components to fail. Use React state (useState, useReducer) for ALL data storage.
REACT ERROR HANDLING REQUIREMENTS (NON-NEGOTIABLE):
- EVERY React component MUST have error boundaries
- EVERY async operation MUST use try/catch blocks
- EVERY API call MUST handle network errors and timeouts
- EVERY component MUST have fallback UI for error states
- EVERY error MUST be logged to console with ERROR: prefix
- EVERY component MUST gracefully degrade when data is unavailable
- NO operation is too simple to skip error handling
REACT COMPONENT STRUCTURE REQUIREMENTS:
- EVERY component MUST be a single file with change log at top
- EVERY component MUST be short: 200 lines MAX, 300 lines ABSOLUTE LIMIT
- EVERY component MUST do ONE thing only - break complex logic into multiple files
- EVERY component MUST have clear prop validation
- EVERY component MUST handle loading and error states
- EVERY component MUST use functional components with hooks
- NO class components - use functional components only
- NO IDE ASSUMPTION - Code must be readable and editable in basic text editors
FILE ORGANIZATION - AUDIENCE-BASED STRUCTURE:
Organize by audience/purpose, NOT by technical type:
src/ ├── audiences/ │ ├── landowners/ # Stories, financial projections, land value │ │ ├── LandownerStory.jsx │ │ ├── ROICalculator.jsx │ │ └── LandValueWidget.jsx │ ├── politicians/ # Policy frameworks, economic impact │ │ ├── EconomicImpact.jsx │ │ ├── PolicyFramework.jsx │ │ └── CommunityBenefits.jsx │ ├── financial/ # Investment models, risk assessments │ │ ├── PortfolioReturns.jsx │ │ ├── RiskAssessment.jsx │ │ └── FinancialProjections.jsx │ ├── technical/ # Engineering specs, implementation │ │ ├── TechSpecs.jsx │ │ ├── DataCenterDetails.jsx │ │ └── RoboticsTimeline.jsx │ └── workers/ # Job transformation stories │ ├── WorkerStories.jsx │ ├── TrainingPrograms.jsx │ └── EquityDistribution.jsx ├── shared/ │ ├── components/ # Reusable UI pieces │ │ ├── DataTable.jsx # For HUD data, housing authorities │ │ ├── SortableWidget.jsx │ │ ├── ErrorBoundary.jsx │ │ └── LoadingSpinner.jsx │ ├── data/ # Static data and constants │ │ ├── sampleData.js # Example datasets for development │ │ ├── constants.js # Fixed values, API endpoints │ │ └── mockData.js # Mock data for testing │ └── utils/ # Helper functions │ ├── formatters.js # Data formatting utilities │ ├── validators.js # Input validation │ └── apiHelpers.js # Future API integration helpers └── App.jsx # Main application component
REACT COMPONENT CHANGE LOG TEMPLATE:
/* CHANGE LOG File: /src/audiences/landowners/ROICalculator.jsx Document Type: React Functional Component Purpose: Interactive ROI calculator for landowner equity returns Props: { landValue: number, acreage: number } State: Local calculation state using useState Dependencies: React, shared/utils/formatters.js Version History: 2025-05-31 v1.1 - Added error handling for invalid inputs 2025-05-31 v1.0 - Initial creation with basic ROI calculation */
REACT ERROR BOUNDARY TEMPLATE - USE FOR ALL MAJOR SECTIONS:
/* CHANGE LOG File: /src/shared/components/ErrorBoundary.jsx Document Type: React Error Boundary Component Purpose: Catch and handle React component errors gracefully Dependencies: React */ import React from 'react'; class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false, error: null }; } static getDerivedStateFromError(error) { console.error('ERROR: ErrorBoundary caught error:', error); return { hasError: true, error }; } componentDidCatch(error, errorInfo) { console.error('ERROR: ErrorBoundary details:', error, errorInfo); } render() { if (this.state.hasError) { return ( <div style="padding: 20px; border: 1px solid red;"> <h3>Something went wrong</h3> <p>{this.props.fallbackMessage || 'Please try refreshing the page.'}</p> </div> ); } return this.props.children; } } export default ErrorBoundary;
FUNCTIONAL COMPONENT TEMPLATE - SHORT & TEXT EDITOR FRIENDLY:
/* CHANGE LOG File: /src/audiences/[audience]/ComponentName.jsx Document Type: React Functional Component Purpose: Brief description of component purpose Props: { prop1: type, prop2: type } State: Description of state management Dependencies: List key imports Lines: Keep under 200, max 300 Version History: 2025-05-31 v1.0 - Initial creation */ import React, { useState, useEffect } from 'react'; const ComponentName = ({ prop1, prop2 }) => { // 1. State (keep minimal) const [data, setData] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); // 2. Input validation useEffect(() => { if (!prop1) { console.error('ERROR: ComponentName - Missing required prop1'); setError('Missing required data'); return; } console.log('DEBUG: ComponentName - Starting load'); loadData(); }, [prop1, prop2]); // 3. Simple data loading const loadData = async () => { try { setLoading(true); setError(null); // Simple processing - if complex, move to separate file const result = processSimpleData(prop1, prop2); setData(result); console.log('DEBUG: ComponentName - Success'); } catch (err) { console.error('ERROR: ComponentName - Failed:', err); setError('Loading failed'); } finally { setLoading(false); } }; // 4. Simple helper (if complex, move to utils/ folder) const processSimpleData = (input1, input2) => { return { processed: true, input1, input2 }; }; // 5. Simple render - all states handled if (error) { return ( <div className="p-4 border border-red-300 bg-red-50"> <p className="text-red-700">Error: {error}</p> </div> ); } if (loading) return <div className="p-4">Loading...</div>; if (!data) return <div className="p-4">No data</div>; return ( <div className="p-4"> <h3 className="text-lg font-semibold mb-2">Component Title</h3> <p className="text-gray-700">{data.input1}</p> </div> ); }; export default ComponentName; // TOTAL LINES: ~70 (well under 200 limit) // IF APPROACHING 200 LINES: Split into multiple files
TAILWIND CSS STANDARDS - PROFESSIONAL & ACCESSIBLE:
- Use utility classes directly in JSX - No separate CSS files unless absolutely necessary
- Professional color palette only: grays (gray-50 to gray-900), blues (blue-50 to blue-900), minimal accents
- NO flashy animations or effects - Simple hover states only (hover:bg-gray-100)
- Responsive design: Mobile-first approach (sm:, md:, lg: breakpoints)
- Accessibility required: Proper contrast ratios, focus states
- Typography hierarchy: text-xs to text-4xl, font-normal to font-bold only
TAILWIND COMPONENT EXAMPLE - PROFESSIONAL DATA TABLE:
const DataTable = ({ data, columns, onSort }) => { return ( <div className="overflow-x-auto"> <table className="min-w-full bg-white border border-gray-200"> <thead className="bg-gray-50"> <tr> {columns.map(col => ( <th key={col.key} className="px-4 py-2 text-left text-sm font-medium text-gray-900 border-b border-gray-200 hover:bg-gray-100 cursor-pointer" onClick={() => onSort(col.key)} > {col.label} </th> ))} </tr> </thead> <tbody> {data.map((row, index) => ( <tr key={index} className="hover:bg-gray-50"> {columns.map(col => ( <td key={col.key} className="px-4 py-2 text-sm text-gray-700 border-b border-gray-100"> {row[col.key]} </td> ))} </tr> ))} </tbody> </table> </div> ); };
DATA INTEGRATION STRATEGY - STATIC TO DYNAMIC:
Phase 1: Static Presentation (Current Need)
- Hard-coded data in JavaScript files for immediate deployment
- Focus on content presentation and user experience
- Build reusable components for future data integration
Phase 2: Data Integration (Future - HUD, Housing Authorities)
- API integration with your Python backend
- Dynamic data loading and caching strategies
- Real-time filtering and sorting capabilities
- Data validation and error recovery
EXAMPLE: SIMPLE HOUSING AUTHORITY WIDGET (UNDER 200 LINES):
/* File: /src/shared/components/HousingAuthorityTable.jsx Purpose: Sortable table for housing authority data Props: { authorities: array } Lines: ~150 (well under limit) */ import React, { useState } from 'react'; const HousingAuthorityTable = ({ authorities = [] }) => { const [sortField, setSortField] = useState('name'); const [sortDirection, setSortDirection] = useState('asc'); const [sizeFilter, setSizeFilter] = useState('all'); // Simple sorting const sortedData = [...authorities] .filter(auth => sizeFilter === 'all' || auth.size === sizeFilter) .sort((a, b) => { const aVal = a[sortField]; const bVal = b[sortField]; const direction = sortDirection === 'asc' ? 1 : -1; return aVal < bVal ? -direction : direction; }); const handleSort = (field) => { setSortDirection(sortField === field && sortDirection === 'asc' ? 'desc' : 'asc'); setSortField(field); }; if (!authorities.length) { return <div className="p-4">No housing authorities data available</div>; } return ( <div className="w-full"> {/* Simple filter */} <div className="mb-4"> <select value={sizeFilter} onChange={(e) => setSizeFilter(e.target.value)} className="border border-gray-300 rounded px-3 py-1" > <option value="all">All Sizes</option> <option value="small">Small</option> <option value="medium">Medium</option> <option value="large">Large</option> </select> </div> {/* Simple table */} <table className="w-full border border-gray-200"> <thead className="bg-gray-50"> <tr> <th onClick={() => handleSort('name')} className="p-2 text-left cursor-pointer hover:bg-gray-100"> Name {sortField === 'name' ? (sortDirection === 'asc' ? '↑' : '↓') : ''} </th> <th onClick={() => handleSort('state')} className="p-2 text-left cursor-pointer hover:bg-gray-100"> State {sortField === 'state' ? (sortDirection === 'asc' ? '↑' : '↓') : ''} </th> <th onClick={() => handleSort('units')} className="p-2 text-left cursor-pointer hover:bg-gray-100"> Units {sortField === 'units' ? (sortDirection === 'asc' ? '↑' : '↓') : ''} </th> <th onClick={() => handleSort('hudRating')} className="p-2 text-left cursor-pointer hover:bg-gray-100"> HUD Rating {sortField === 'hudRating' ? (sortDirection === 'asc' ? '↑' : '↓') : ''} </th> </tr> </thead> <tbody> {sortedData.map((auth, index) => ( <tr key={auth.id || index} className="border-b hover:bg-gray-50"> <td className="p-2">{auth.name}</td> <td className="p-2">{auth.state}</td> <td className="p-2">{auth.units?.toLocaleString()}</td> <td className="p-2">{auth.hudRating}</td> </tr> ))} </tbody> </table> <p className="mt-2 text-sm text-gray-600"> Showing {sortedData.length} of {authorities.length} authorities </p> </div> ); }; export default HousingAuthorityTable; // TOTAL: ~80 lines - Perfect for text editor editing
SIMPLICITY PRINCIPLE FOR REACT (CRITICAL FOR TEXT EDITOR WORKFLOW):
- One component = One purpose - Don't combine unrelated functionality
- 200 line limit - If approaching 200 lines, split into separate files immediately
- 300 line absolute maximum - NO exceptions, break into smaller components
- Props should be simple - Avoid complex object structures when possible
- State should be minimal - Only store what actually changes
- NO premature optimization - Build working components first, optimize later
- Clear naming - Component and variable names should be self-explanatory
- Text editor friendly - No complex IDE-dependent patterns or imports
- Easy navigation - Find what you need quickly without IDE search tools
INTEGRATION WITH EXISTING PYTHON BACKEND:
- API endpoints: React calls Python Flask routes for data
- Error handling: Handle Python errors gracefully in React
- Development workflow: Static development, then connect APIs
- Data flow: Python processes data, React displays it beautifully
REMINDERS:
- Change logs MUST be visible in browser view-source
- Error boundaries around ALL major component sections
- Console logging for ALL operations (success and failure)
- NO localStorage/sessionStorage - use React state only
- SIMPLICITY OVER CLEVERNESS - Readable code over fancy patterns
- Build for your sophisticated audience - clean, professional, functional