Building a rich user experience in the browser can be a challenging task, one that often requires a significant amount of JavaScript code. As the needs and ambitions of our application grows, so does the complexity of our JavaScript code. It is therefore no surprise how often developers have revised how we think about, and write, JavaScript apps.
WordPress plugin developers have it worse. The environment that we target is neither a server that we control, nor one with complete control over the entire page. While it’s very possible to use a JavaScript framework successfully in a WordPress plugin, it can also be remarkably easy to end up with a project whose scale and complexity is beyond what you intended or expected.
But what if it didn’t need to be this way? In this article, we’ll be exploring how modern web UIs are built with JavaScript, the difficulties that developers face, and the alternative offered by HTMX. In particular, we’ll be taking a look at why HTMX and WordPress may be a match made in heaven.
How we got here
Before JavaScript, browsers were basically just glorified document readers. As such, most experiences on the web were ‘multi-page applications’, or MPAs for short. MPAs are web applications that consist of multiple HTML documents, one for each page in the application. As the user uses the application, they are shown different documents with different available actions.
MPAs are very straightforward to build. Navigation is done using tags to link to other documents, and user input can be captured with a
Our page will render a single, empty
const rootEl = document.getElementById("books-app");
const root = ReactDOM.createRoot(rootEl);
root.render( );
function BooksApp() {
return (
My Books
...
);
}
So how do we list the books that are stored in the database? The code to do that is on the server, so we need a way to call it and get its result.
To do that, we can expose a JSON API from the server. The React app can then make a request at our API’s URL, receive the books in JSON format, then render the list. For this example, let’s assume that we’ve added an endpoint to the WordPress REST API:
GET https://my-wp-site.com/wp-json/books
{
"books": [
{
"id": 15,
"title": "Mistborn",
"author": "Brandon Sanderson",
},
{
"id": 44,
"title": "The Hobbit",
"author": "J. R. R. Tolkien",
},
]
}
We can then write a React component that fetches the books and renders them as a list:
function BookList() {
const [books, setBooks] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(
function () {
setIsLoading(true);
fetch("https://my-wp-site.com/wp-json/books")
.then((res) => res.json())
.then((data) => setBooks(data.books))
.else((error) => setError(error))
.finally(() => setIsLoading(false));
},
[setBooks, setIsLoading],
);
if (isLoading) {
return Loading...;
}
if (error) {
return Error: {error};
}
return (
-
{books.map((book) => (
{book.title}
))}
);
}
But this solution is too naive, and yields a rough user experience. It does not cater for state changes after the component un-mounts, caching the response, retrying failed queries, or prevent stale state from overwriting more recent state. In fact, the way we are using fetch()
in a React effect is generally discouraged.
In many ways, this can be worse than a traditional MPA. So to do this correctly, we’ll need to implement a few more things in our client. Or, more realistically, use 3rd party packages.
But all of this is starting to feel like a disproportionate amount of effort just to render a list of books. Do we really need to create a JavaScript app and a JSON API to create a smooth user experience?
Let’s contrast this with an MPA, where rendering the list of books can be accomplished in just a few lines of PHP code, without any dependencies:
But of course, this is not a fair comparison. This list of books is just static HTML; it is not reactive to state changes or user input.
If we want to have a SPA-like experience while also rendering the HTML on the server, where our code has immediate access to the database, we’ll need to find a way to have the server-rendered HTML find its way to the browser and replace the previous list of books. But achieving this without any JavaScript code is currently impossible, so we’d have to bite the bullet and use JavaScript anyway.
But we don’t need to write it ourselves.
Introducing HTMX
HTMX is a small JavaScript library that primarily does one thing: allow HTML to request new HTML from the server. It does this using new attributes, which allow us to tell HTMX where to get the new HTML from, what to swap it out with, and what triggers the swapping. It acts as a bridge between our HTML server and the page in the browser.
This is a vastly different way of thinking about SPAs, since we are not building a client JavaScript application to update the current page. Instead, we simply add some HTML attributes to tell HTMX how we want the page to change when certain events happen.
Even without HTMX, you can already change what is shown on the screen using just HTML, albeit in a very limited way. You’re already familiar with this HTML feature: the humble link element.
View books
A link element gives the browser all of the information that is necessary is carry out navigation. When it is clicked, the browser takes the href
from the element, makes a request at that URL, downloads the response and, assuming that it contained HTML, replaces the contents of the page with the new HTML.
The