Bhread now lazy loads posts!

What is lazy loading?

Lazy loading is a technique for waiting to load certain parts of a webpage — especially images — until they are needed. source

Visiting will show 6 posts. If you reach the bottom of the page, it will load 8 more. The process repeats until no more posts are found. This is also known as infinite scrolling.

Why lazy load posts?

lazy-loading-110kb loads a 100kb file when the home page is visited. This was because at the time of testing, the total numer of posts is around 30. It loads all 30 of them in a single visit. This is a waste of bandwidth as most of the time, the user won’t scroll far down anyway.

The 100kb file takes a long time to load (~1sec).

Now, it loads a 26kb file (still a bit big) in 350milsec. This is a big improvement in useability. It’s the difference between snappy and sluggish.


Still supports no javascript


Don’t have javascript? You’re still covered! Bhread will display a ‘Next page’ link so users without js can still use Bhread.


With HTMX, it’s pretty easy.

First, send the user a list containing a list item with htmx:


    <li> {{ post id=1}} </li>
    <li> {{ post id=2}} </li>
    <li> {{ post id=3}} </li>
    <li> {{ post id=4}} </li>
    <li hx-get="/htmx-home?id=4" hx-trigger="intersect once" hx-swap="outerHTML" >
        {{ post-loading-skeleton }} 

What this does: render posts 1-4, then issue a get request to /htmx-home when the last element is seen by the user (intersect). Send the id of the last post. If a response is received, replace THIS item (li) with the new items.

Then, /htmx-home receives the id and returns the new posts which follow the id of the last post.


<li> {{ post id=5 }} </li>
<li> {{ post id=6 }} </li>
<li> {{ post id=7 }} </li>
<li> {{ post id=8 }} </li>
<li hx-get="/htmx-home?id=8" hx-trigger="intersect once" hx-swap="outerHTML" >
    {{ post-loading-skeleton }} 

The resulting html is this:

    <li> {{ post id=1 }} </li>
    <li> {{ post id=2 }} </li>
    <li> {{ post id=3 }} </li>
    <li> {{ post id=4 }} </li>
    <li> {{ post id=5 }} </li>
    <li> {{ post id=6 }} </li>
    <li> {{ post id=7 }} </li>
    <li> {{ post id=8 }} </li>
    <li hx-get="/htmx-home?id=8" hx-trigger="intersect once" hx-swap="outerHTML" >
        {{ post-loading-skeleton }} 

The process continues until no more posts are found.

How about noJS?

The good thing about HTMX is that it allows the site to degrade well when JS is disabled. It’s a bit more complicated to implement but I expect Bhread to deal with mostly static sites. Ones that don’t need JS to function. So I think it’s worth the effort to implement this. Your mileage may vary.

To outline how this is implemented, here’s a rough step-by-step:

  • In the backend, detect if request is coming with an HTMX request header. If not present, the user has JS disabled.
  • In the frontend, add a <noscript> tag that includes a button labeled ’next’. This button should include the ID of the last item that was rendered.
  • When generating the html, check if JS is enabled in the request.
  • If yes, add the htmx-enabled element that will request for new items when seen
  • If not, don’t add anything.
  • The <noscript> element will still be present whether JS is on or not. We don’t need to worry about this because it takes advantage of the fact that this block will not be shown unless JS is disabled.
  • Now make both /home and /htmx-home accept an ID argument which is the ID of the last element rendered.
  • If JS is enabled, use the route for htmx: /htmx-home, passing the ID and returning a new list of partials that continues from the ID
  • The client receives this and appends it to the current list of items.
  • If JS is disabled, use the normal route for the home page /home, passing the ID and returning a new page containing the new items that follow the ID.
  • When the button for ’next page’ is pressed, the page will reload containing the new posts and another ’next page’ button.

If you’re interested in this, the code is FOSS, the backend code for this is here:

and the HTML template is here:


Stay updated

For more updates, subscribe to the bhread blog’s RSS feed, visit or join the discord server.