Infinite Scroll

Load content dynamically as users scroll
Learn how to implement infinite scroll patterns using hyperscript's scroll events and intersection observers. Perfect for feeds, news lists, and content-heavy pages!
scroll intersection dynamic loading async

Infinite News Feed

Scroll to the bottom to load more items automatically:

10
Items Loaded
1
Load Count
0%
Scroll Position
  • #1 Initial Load
    Welcome to Infinite Scroll
    Scroll down to load more articles automatically. This example demonstrates how to implement infinite scroll using hyperscript's scroll event handling.
  • #2 Initial Load
    How Infinite Scroll Works
    The scroll event monitors your position in the container. When you get close to the bottom, new content is automatically fetched and added to the list.
  • #3 Initial Load
    Performance Considerations
    This implementation uses a loading flag to prevent multiple simultaneous loads. It also calculates distance from bottom to trigger loading at the right time.
  • #4 Initial Load
    Dynamic Content Generation
    New items are created using hyperscript's template literals and make command. Each item includes a unique number, timestamp, and content.
  • #5 Initial Load
    User Experience
    Loading indicators provide feedback during content fetching. The scroll position percentage helps users understand their position in the content.
  • #6 Initial Load
    State Management
    Local state variables track the current page, loading status, and total items. This ensures consistent behavior across multiple load cycles.
  • #7 Initial Load
    Pagination Alternative
    Infinite scroll is a modern alternative to traditional pagination. It's perfect for social media feeds, news sites, and content discovery platforms.
  • #8 Initial Load
    Accessibility
    Always provide keyboard navigation and screen reader announcements for dynamically loaded content. Consider a "load more" button as a fallback.
  • #9 Initial Load
    Keep Scrolling!
    Scroll down to see the infinite scroll in action. New content will load automatically as you approach the bottom of the container.
  • #10 Initial Load
    Almost There...
    Just a few more scrolls and you'll trigger the first automatic load. Watch the loading indicator appear and new items slide in smoothly!
Loading more items...
You've reached the end! No more items to load.

The Code

Infinite Scroll Container:

<div class="scroll-container" _="init set :currentPage to 1 set :maxPages to 10 set :loading to false end on scroll set scrollTop to my scrollTop set scrollHeight to my scrollHeight set clientHeight to my clientHeight set distanceFromBottom to scrollHeight - (scrollTop + clientHeight) if distanceFromBottom < 100 and :loading is false set :loading to true add .active to #loading -- Simulate API call wait 1.5s -- Load more items increment :currentPage repeat 10 times make a <li>New Item</li> called newItem put newItem at end of #content-list end remove .active from #loading set :loading to false end end"> <ul id="content-list"> <!-- Initial items --> </ul> <div id="loading" class="loading-indicator">Loading...</div> </div>

With API Fetching:

<div _="on scroll set distanceFromBottom to my scrollHeight - (my scrollTop + my clientHeight) if distanceFromBottom < 100 and :loading is false set :loading to true fetch `/api/items?page=${:currentPage}` as json put result into items repeat for item in items make a <li>${item.title}</li> called newItem put newItem at end of #list end increment :currentPage set :loading to false end"> </div>

How it works:

Key Concepts:

Scroll Calculations:

-- Get scroll metrics set scrollTop to element.scrollTop set scrollHeight to element.scrollHeight set clientHeight to element.clientHeight -- Calculate distance from bottom set distanceFromBottom to scrollHeight - (scrollTop + clientHeight) -- Calculate scroll percentage set scrollPercent to (scrollTop / (scrollHeight - clientHeight)) * 100 -- Check if near bottom (within 100px) if distanceFromBottom < 100 -- Load more content end

Advanced Patterns:

<!-- Intersection Observer (more efficient) --> <div id="sentinel" _="init set observer to new IntersectionObserver( function(entries) { if (entries[0].isIntersecting) { // Load more content } } ) call observer.observe(me) end"> </div> <!-- Virtual scrolling for large lists --> <div _="on scroll set visibleStart to Math.floor(scrollTop / itemHeight) set visibleEnd to visibleStart + visibleCount -- Only render visible items for i from visibleStart to visibleEnd if not #{i} exists make item for index i put it into #list end end"> </div> <!-- Debounced scroll handling --> <div _="on scroll if :scrollTimer then clearTimeout(:scrollTimer) end set :scrollTimer to setTimeout( function() { checkLoadMore() }, 200 )"> </div> <!-- Bidirectional infinite scroll --> <div _="on scroll if scrollTop < 100 -- Load older content at top fetch `/api/items?page=${:prevPage--}` as json for item in result make <li>{item}</li> put it at start of #list end else if distanceFromBottom < 100 -- Load newer content at bottom fetch `/api/items?page=${:nextPage++}` as json for item in result make <li>{item}</li> put it at end of #list end end"> </div>

Common Use Cases:

Performance Best Practices:

Accessibility Considerations:

Try it yourself: