Infinite Scroll & Load More
Loading indicators for infinite scroll, load more buttons with variants, progress bars, and end/error states.
Infinite Scroll Loading
Preview
Loading more items...
<div class="infinite-scroll">
<div class="infinite-scroll-spinner">
<div class="infinite-scroll-icon"></div>
<span class="infinite-scroll-text">Loading more items...</span>
</div>
</div> Requires: ux.min.css
<div class="flex flex-col items-center p-6">
<div class="flex items-center gap-4">
<div class="w-6 h-6 border-2 border-base-300 border-t-primary rounded-full animate-spin"></div>
<span class="text-sm text-base-content/60">Loading more items...</span>
</div>
</div> Requires: tw.min.css
// Infinite scroll with IntersectionObserver:
const sentinel = document.querySelector('.infinite-scroll');
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
loadMoreItems(); // Your data fetching function
}
});
observer.observe(sentinel); End & Error States
Preview
Failed to load more items
<div class="flex flex-col gap-4">
<!-- End state -->
<div class="infinite-scroll infinite-scroll-complete">
<div class="infinite-scroll-end-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
</div>
<span class="infinite-scroll-end-text">You've reached the end</span>
</div>
<!-- Error state -->
<div class="infinite-scroll infinite-scroll-error">
<span class="infinite-scroll-error-text">Failed to load more items</span>
<button class="infinite-scroll-retry">Try again</button>
</div>
</div> Requires: ux.min.css
<div class="flex flex-col gap-4">
<!-- End state -->
<div class="flex flex-col items-center p-6 text-base-content/40">
<div class="w-5 h-5 mb-1">
<svg xmlns="http://www.w3.org/2000/svg" class="w-full h-full" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
</div>
<span class="text-sm text-base-content/40">You've reached the end</span>
</div>
<!-- Error state -->
<div class="flex flex-col items-center gap-2 p-6">
<span class="text-sm text-error">Failed to load more items</span>
<button class="text-sm font-medium bg-transparent border-none cursor-pointer text-primary px-4 py-2 hover:underline">Try again</button>
</div>
</div> Requires: tw.min.css
// Retry button handler:
document.querySelector('.infinite-scroll-retry').addEventListener('click', () => {
loadMoreItems(); // Retry your data fetch
}); Scroll Progress Bar
Preview
<div style="position: relative; height: 8px; border-radius: 4px; overflow: hidden;">
<div class="scroll-progress" style="position: relative;">
<div class="scroll-progress-bar" style="width: 65%;"></div>
</div>
</div> Requires: ux.min.css
<div class="relative h-0.75 bg-base-300 rounded-full overflow-hidden">
<div class="h-full bg-primary rounded-full" style="width: 65%;"></div>
</div> Requires: tw.min.css
// Update scroll progress:
window.addEventListener('scroll', () => {
const pct = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100;
document.querySelector('.scroll-progress-bar').style.width = pct + '%';
}); Load More Button
Preview
Showing 10 of 48 items
<div class="flex flex-col gap-4">
<!-- Default (outline) -->
<div class="load-more">
<button class="load-more-btn">Load More</button>
<span class="load-more-status">Showing 10 of 48 items</span>
</div>
<!-- Filled -->
<div class="load-more load-more-filled">
<button class="load-more-btn">Load More</button>
</div>
<!-- Soft -->
<div class="load-more load-more-soft">
<button class="load-more-btn">Load More</button>
</div>
<!-- Ghost -->
<div class="load-more load-more-ghost">
<button class="load-more-btn">Load More</button>
</div>
</div> Requires: ux.min.css
<div class="flex flex-col gap-4">
<!-- Default (outline) -->
<div class="flex flex-col items-center gap-2 py-6">
<button class="inline-flex items-center justify-center gap-2 font-medium cursor-pointer select-none h-11 px-8 text-primary bg-transparent border border-primary rounded-full hover:bg-primary/10 active:scale-[0.98]">Load More</button>
<span class="text-sm text-base-content/40">Showing 10 of 48 items</span>
</div>
<!-- Filled -->
<div class="flex flex-col items-center gap-2 py-6">
<button class="inline-flex items-center justify-center gap-2 font-medium cursor-pointer select-none h-11 px-8 bg-primary text-primary-content border border-primary rounded-full hover:brightness-90 active:scale-[0.98]">Load More</button>
</div>
<!-- Soft -->
<div class="flex flex-col items-center gap-2 py-6">
<button class="inline-flex items-center justify-center gap-2 font-medium cursor-pointer select-none h-11 px-8 bg-primary/10 text-primary border-none rounded-full hover:bg-primary/20 active:scale-[0.98]">Load More</button>
</div>
<!-- Ghost -->
<div class="flex flex-col items-center gap-2 py-6">
<button class="inline-flex items-center justify-center gap-2 font-medium cursor-pointer select-none h-11 px-8 bg-transparent text-primary border-none rounded-full hover:bg-primary/10 active:scale-[0.98]">Load More</button>
</div>
</div> Requires: tw.min.css
// Load more click handler:
document.querySelector('.load-more-btn').addEventListener('click', async () => {
container.classList.add('load-more-loading');
await fetchMoreItems();
container.classList.remove('load-more-loading');
}); Load More with Progress
Preview
All items loaded
<div class="load-more">
<button class="load-more-btn">Load More</button>
<div class="load-more-progress">
<div class="load-more-progress-bar">
<div class="load-more-progress-fill" style="width: 40%;"></div>
</div>
<span>20 of 50</span>
</div>
</div>
<!-- Loading state -->
<div class="load-more load-more-loading">
<button class="load-more-btn">
<span class="load-more-spinner"></span>
Loading...
</button>
</div>
<!-- End state -->
<div class="load-more load-more-end">
<button class="load-more-btn">Load More</button>
<div class="load-more-end-message">All items loaded</div>
</div> Requires: ux.min.css
<!-- With progress -->
<div class="flex flex-col items-center gap-2 py-6">
<button class="inline-flex items-center justify-center gap-2 font-medium cursor-pointer select-none h-11 px-8 text-primary bg-transparent border border-primary rounded-full hover:bg-primary/10 active:scale-[0.98]">Load More</button>
<div class="flex items-center gap-2 text-sm text-base-content/60">
<div class="w-25 h-1 bg-base-300 rounded-sm overflow-hidden">
<div class="h-full bg-primary rounded-sm" style="width: 40%;"></div>
</div>
<span>20 of 50</span>
</div>
</div>
<!-- Loading state -->
<div class="flex flex-col items-center gap-2 py-6">
<button class="inline-flex items-center justify-center gap-2 font-medium select-none h-11 px-8 text-primary bg-transparent border border-primary rounded-full pointer-events-none">
<span class="w-4.5 h-4.5 border-2 border-current border-t-transparent rounded-full animate-spin"></span>
Loading...
</button>
</div>
<!-- End state -->
<div class="flex flex-col items-center gap-2 py-6 pointer-events-none">
<div class="flex items-center gap-2 text-sm text-base-content/40">All items loaded</div>
</div> Requires: tw.min.css
// No JavaScript required for visual states — toggle classes as needed