This document describes the conversion from React SPA to htmx server-rendered application.
The application has been successfully converted from a React single-page application to an htmx-based server-rendered application. This simplification reduces client-side JavaScript, improves initial page load performance, and makes the codebase easier to understand and maintain.
- Client-side SPA with React 18.2.0
- Client-side state management
- JSON API endpoints
- Client-side routing
- Heavy JavaScript bundle
- All rendering in browser
- Server-rendered HTML fragments
- htmx for dynamic updates
- HTML responses from server
- URL-based routing with query params
- Minimal JavaScript (only for geolocation)
- Progressive enhancement
backend/views/layout.tsx- Main layout and app shellbackend/views/planTab.tsx- Plan tab renderingbackend/views/logTab.tsx- Log tab with cardsbackend/views/newRunModal.tsx- New run modal
backend/routes/modals.ts- Modal endpoints
backend/index.http.tsx- Updated to serve HTML, added tab routesbackend/routes/runLogs.ts- Updated to handle both JSON and HTML responses
README.md- Updated tech stack and TODO
These files are no longer used:
frontend/components/App.tsxfrontend/components/PlanTab.tsxfrontend/components/LogTab.tsxfrontend/components/NewRunModal.tsxfrontend/index.tsx
✅ Plan Tab
- Geolocation support
- Weather fetching
- AI recommendations
- Date/time selection
✅ Log Tab
- View all runs
- Edit inline
- Delete runs
- Formatted dates and clothing
✅ New Run Modal
- Automatic geolocation
- Location search
- Weather auto-fetch
- Form submission
✅ Mobile Optimization
- Responsive design
- Touch-friendly
- Fixed floating action button
- Simpler Code: No React state management, hooks, or effects
- Less JavaScript: Minimal client-side code
- Progressive Enhancement: Works without JavaScript for basic functionality
- Better Initial Load: HTML rendered on server
- Easier to Debug: Clear request/response flow
- Better Performance: Less parsing and hydration overhead
- SEO Friendly: Server-rendered content
The htmx version naturally addresses the location lookup performance issue mentioned in the README:
- Non-blocking UI: The page loads immediately with "Getting location..." placeholder
- Background fetching: Location and weather fetch in background
- User can interact: Forms are usable while loading
- Progressive enhancement: Content appears as it becomes available
hx-get- Fetch HTML fragmentshx-post- Submit formshx-put- Update recordshx-delete- Delete recordshx-target- Specify where to put responsehx-swap- Control swap behaviorhx-trigger- Event triggershx-include- Include form valueshx-push-url- Update browser URLhx-confirm- Confirmation dialogs
While we eliminated React, some vanilla JavaScript is still needed for:
- Geolocation API: Browser location access
- Modal interactions: Toggle location search panel
- Weather updates: Coordinate weather API calls
- Location search: Geocoding workflow
All JavaScript is embedded in templates where needed, keeping logic close to the UI.
- Visit the main page - should see Plan tab with location loading
- Click Log tab - should see all runs
- Click + button - modal opens with geolocation
- Change date - weather updates
- Search location - updates weather
- Submit form - creates run and closes modal
- Edit a run - inline editing
- Delete a run - confirmation and removal
The migration maintains backward compatibility with JSON API endpoints, so external clients or tools that depend on the JSON API will continue to work. The endpoints detect content type and respond accordingly:
application/json→ JSON response (old behavior)- HTML request (htmx) → HTML fragment (new behavior)
- Remove old React files after confirming everything works
- Consider implementing server-side caching for geocoding (see README TODO)
- Add loading indicators/spinners for better UX feedback
- Add success notifications (snackbar) after save operations
- Test thoroughly on mobile devices
No changes needed to deployment process. The app still:
- Uses Hono as the HTTP framework
- Runs on Val Town
- Requires
ANTHROPIC_API_KEYenvironment variable - Entry point is
backend/index.http.tsx