Infinite scrolling with HTMX
During the development of my multimedia platform, I quickly realised that traditional pagination felt outdated. I wanted a seamless, modern way for users to browse media collections. ReactJS and similar frameworks felt excessive for my needs, so I kept searching for a middle ground – and that’s when I found HTMX.
What is HTMX?
HTMX is like a toolkit that extends your HTML, letting you build interactive web pages without heavy JavaScript frameworks. With just a few attributes, you can sprinkle AJAX, CSS transitions, WebSockets, and server-sent events into your HTML elements, enabling actions like updating parts of the page and submitting forms without reloadin
Implementing Infinite Scroll with HTMX
To create an infinite scroll for my media collection landing page, I used HTMX’s attributes to dynamically load more content as users scroll. Here’s how I did it:
Key Attributes:
Attribute | Description | Documentation Link |
---|---|---|
hx-get | Triggers a GET request to a specified URL | Link |
hx-swap | Specifies how the response content is inserted into the page | Link |
hx-trigger | Determines the event that triggers the action (e.g., intersect on scroll which we will use ) | Link |
Example Code:
<div class="movie"
hx-get="/content/movies?page=2"
hx-trigger="intersect"
hx-swap="afterend">
</div>
Backend Code Explanation
To handle these requests, I created a Go endpoint that paginates content data:
func getMovies(rw http.ResponseWriter, req *http.Request) {
const maxMoviesPerRequest = 20
// obtain movies, etc.
pageNumber := 1
totalMovies := len(movies)
if totalMovies > maxMoviesPerRequest {
pageParam := req.URL.Query().Get("page")
if pageParam != "" {
pageNumber, _ = strconv.Atoi(pageParam)
}
}
// ...
startIndex := (pageNumber - 1) * maxMoviesPerRequest
endIndex := startIndex + maxMoviesPerRequest
if endIndex > totalMovies {
endIndex = totalMovies
}
if req.Header.Get("HX-Request") == "true" {
// Render partial template
} else {
// Render main template
}
}
Main Template Structure
The main template displays the maxMoviesPerRequest number in a grid. The last element of the grid will have the HTMX trigger. Once it is displayed on screen, it will trigger a GET request, rendering further items appended after the triggering element, and so on.
<main>
<div class="movie-list">
{{ range $index, $element := .Movies }}
{{ if and (eq $index $.LastMovieIndex) (gt $.TotalPages 1) }}
<div class="movie"
hx-get="/content/movies?page={{ add $.CurrentPage 1 }}"
hx-trigger="intersect"
hx-swap="afterend">
{{ else }}
<div class="movie">
{{ end }}
<div class="movie-poster-container">
<img src="{{ $element.Poster }}" class="movie-poster" id="poster-item">
</div>
<p>{{ $element.Title }}</p>
</div>
{{ end }}
</div>
</main>
Conclusion
HTMX makes adding modern, dynamic interactions to your web app straightforward. Infinite scroll is just one example; with minimal code, you can create a smooth user experience that would otherwise require heavier tools. Try HTMX for your next project and see how it can simplify your development workflow.