# Infinite scroll without breaking the back button ## Auto-Load Infinite Scroll (Progressive Enhancement) ## Overview The "Load More" button now has a stable ID (`load-more-trigger`) that enables progressive enhancement with auto-loading via IntersectionObserver. ## Current Implementation The button is accessible via: ```html Load More Posts ``` ## Progressive Enhancement: Auto-Load on Scroll You can optionally add JavaScript to automatically load more posts when the user scrolls near the button. This is **completely optional** - the button works perfectly without it. ### Implementation **File**: `app/javascript/application.js` (or your main JS file) ```javascript // Auto-load infinite scroll when "Load More" button becomes visible document.addEventListener('turbo:load', () => { const loadMoreButton = document.getElementById('load-more-trigger'); if (!loadMoreButton) return; // Create IntersectionObserver to watch when button enters viewport const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { // When button is visible (threshold: 10% visible) if (entry.isIntersecting) { // Click the button to load more posts loadMoreButton.click(); } }); }, { threshold: 0.1, // Trigger when 10% of button is visible rootMargin: '200px' // Start loading 200px before button is visible }); // Start observing the button observer.observe(loadMoreButton); }); ``` ### How It Works 1. **User scrolls down** the blog posts page 2. **IntersectionObserver detects** when "Load More" button enters viewport 3. **Automatically clicks** the button (triggers Turbo Frame request) 4. **New posts load** via Turbo Stream (same as manual click) 5. **Process repeats** until all posts are loaded ### Benefits ✅ **Progressive Enhancement**: Works without JS, enhanced with JS ✅ **Better UX**: No need to click "Load More" manually ✅ **Stable ID**: Button always has `id="load-more-trigger"` ✅ **Turbo Compatible**: Uses Turbo events (`turbo:load`) ✅ **Performance**: Only loads when user scrolls near bottom ### Configuration Options ```javascript { threshold: 0.1, // Trigger when 10% visible (0.0 to 1.0) rootMargin: '200px' // Start loading 200px before visible } ``` **Adjust based on your needs:** - **Higher threshold** (e.g., `0.5`) = Load when button is 50% visible - **Larger rootMargin** (e.g., `'500px'`) = Start loading earlier - **Lower threshold** (e.g., `0.05`) = Load when button is barely visible ### Loading Indicator (Optional) You can add a loading state: ```javascript document.addEventListener('turbo:load', () => { const loadMoreButton = document.getElementById('load-more-trigger'); if (!loadMoreButton) return; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { // Add loading state loadMoreButton.disabled = true; loadMoreButton.innerHTML = 'Loading...'; // Click to load loadMoreButton.click(); } }); }, { threshold: 0.1, rootMargin: '200px' }); observer.observe(loadMoreButton); // Re-enable button after Turbo Stream completes document.addEventListener('turbo:frame-load', () => { const button = document.getElementById('load-more-trigger'); if (button) { button.disabled = false; button.innerHTML = 'Load More Posts'; } }); }); ``` ### Error Handling (Optional) ```javascript document.addEventListener('turbo:load', () => { const loadMoreButton = document.getElementById('load-more-trigger'); if (!loadMoreButton) return; let isLoading = false; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting && !isLoading) { isLoading = true; loadMoreButton.click(); } }); }, { threshold: 0.1, rootMargin: '200px' }); observer.observe(loadMoreButton); // Reset loading state after frame loads document.addEventListener('turbo:frame-load', () => { isLoading = false; }); // Handle errors document.addEventListener('turbo:frame-missing', () => { isLoading = false; console.error('Failed to load more posts'); }); }); ``` ## Browser Compatibility IntersectionObserver is supported in: - ✅ Chrome 51+ - ✅ Firefox 55+ - ✅ Safari 12.1+ - ✅ Edge 15+ For older browsers, you can use a polyfill or fall back to manual clicking. ## Summary The stable `id="load-more-trigger"` enables: - ✅ **Auto-loading** via IntersectionObserver - ✅ **Progressive enhancement** (works without JS) - ✅ **Future enhancements** (loading states, error handling, etc.) - ✅ **Consistent behavior** across page loads and Turbo Stream updates **Note**: Auto-loading is **optional**. The infinite scroll works perfectly without JavaScript - users can manually click "Load More" if they prefer.