How to create Conditional HX-Triggers based on Element Visibility with HTMX
Date: 2024-10-23 | create | tech | htmx | projects | one-million-checkboxes |
I recently released One Million Checkboxes - a globally synced display of 1 million checkboxes using HTMX to drive the UI. Under the hood it uses polling to rerender sections of the grid. However rendering everything at once is too costly (~5mb per reload) so I needed to implement conditionals to only pull UI sections it needs (~3.6kb per reload) based on what the user's browser is looking at.
I implemented this using HTMX's trigger conditionals to call a custom function determining if the target element was visible or not.
Here we'll explore how this works so you can implement something similar in your own app.
App Overview
First an overview of One Million Checkboxes to give you a better idea of how this visibility conditional works and fits into the broader system.
- A display of One Million Checkboxes
- Split into grid sections of 1000 checkboxes
- Each grid has a unique Id of format
CheckboxGrid_STARTINDEX
which we use as an HTMX Target - Each grid has its own HTMX poller using
hx-trigger
- On trigger, it checks if it's visible using HTMX conditionals and if so fetches the new version of the grid and swaps out its innerHTML
The grid HTML looks like this:
<div
id="CheckboxGrid_999000"
hx-get="/?start=999000"
hx-target="#CheckboxGrid_999000"
hx-swap="innerHTML"
hx-trigger="every 3.641347793457788s [isElementVisible(CheckboxGrid_999000)]"
class="grid place-items-center">
<!-- Checkbox HTML omitted for clarity -->
</div>
Notable:
hx-trigger
every x seconds- Uses a helper function
isElementVisible
with the element's id as a conditional to see if it should trigger or not
HTMX Conditionals on Element Visibility
HTMX allows conditional triggering with the syntax hx-trigger="TRIGGER [CONDITIONAL]"
. It currently does not have a built-in conditional for whether the element is visible or not so I had to roll my own.
isElementVisible
takes in a reference to an HTML element and tries to determine if the element is visible by comparing the window with the bounding box of the element. Honestly this API is confusing as both the window and element positions change on scroll but I've cross-referenced it with several answers and it works in prod so seems to work as expected.
function isElementVisible(element) {
if(!element) {
return false
}
const elementRectangle = element.getBoundingClientRect()
const elementTop = elementRectangle.top
const elementBottom = elementTop + elementRectangle.height
// Source: https://stackoverflow.com/questions/487073/how-to-check-if-element-is-visible-after-scrolling
const isVisible = elementTop < window.innerHeight && elementBottom >= 0
return isVisible
}
To call this function with HTMX:
- Include the function on the webpage (script tag or import)
- Call this function inside
hx-trigger
as a conditional, passing in the element's id
Next
You can see this code in action yourself on One Million Checkboxes.
If you liked this post you might also like:
Want more like this?
The best / easiest way to support my work is by subscribing for future updates and sharing with your network.