MervCodes

Tech Reviews From A Programmer

HTMX Guide: Build Modern Web Apps Without JavaScript Frameworks

1 min read

Why HTMX Is Changing the Way We Build for the Web

For over a decade, the default answer to "how do I build a modern web app?" has been to reach for a JavaScript framework. React, Vue, Angular, Svelte — each comes with its own ecosystem, build tooling, state management patterns, and learning curve. HTMX offers a radically different approach: what if HTML itself could handle the interactivity your users actually need?

HTMX is a small (~14KB min+gzip) JavaScript library that gives you access to AJAX, CSS transitions, WebSockets, and Server-Sent Events directly in HTML using attributes. Instead of writing JavaScript to fetch data and manipulate the DOM, you declare what should happen right in your markup. The server sends back HTML, not JSON, and HTMX swaps it into the page.

The result is simpler architecture, less client-side code, and applications that feel fast and modern — without a single line of framework boilerplate.

Getting Started With HTMX

Adding HTMX to a project takes one line. There is no build step, no npm install, and no bundler configuration.

<script src="https://unpkg.com/[email protected]"></script>

That is the entire setup. You can also self-host the file or install it via npm if your project uses a bundler, but it is entirely optional.

Once the script is loaded, you have access to a set of HTML attributes that replace the vast majority of custom JavaScript you would otherwise write.

Core Concepts: The Four Essential Attributes

HTMX revolves around a small set of attributes that answer four questions about any interaction:

1. What triggers the request?

The hx-trigger attribute defines the event that initiates a server call. By default, forms use submit and most other elements use click, but you can specify any DOM event.

<input type="text" name="search" hx-trigger="keyup changed delay:300ms" hx-get="/search" hx-target="#results">

This input fires a GET request 300 milliseconds after the user stops typing — a live search with zero JavaScript.

2. What HTTP method and URL?

Use hx-get, hx-post, hx-put, hx-patch, or hx-delete to specify the request method and endpoint.

<button hx-delete="/items/42" hx-confirm="Are you sure?">Delete Item</button>

3. Where does the response go?

The hx-target attribute tells HTMX which element to update with the server's response. It accepts any CSS selector.

<button hx-get="/notifications" hx-target="#notification-panel">Check Notifications</button>

4. How is the content inserted?

The hx-swap attribute controls how the returned HTML is placed relative to the target element. Options include innerHTML (default), outerHTML, beforeend, afterbegin, beforebegin, afterend, delete, and none.

<form hx-post="/comments" hx-target="#comment-list" hx-swap="beforeend">
    <textarea name="body"></textarea>
    <button type="submit">Post Comment</button>
</form>

This appends each new comment to the end of the list without replacing existing comments.

Building a Real Feature: Inline Editing

Here is a practical example that demonstrates how HTMX replaces what would typically require a React component with state management.

The display view:

<div id="contact-1">
    <span>Jane Smith</span>
    <span>[email protected]</span>
    <button hx-get="/contacts/1/edit" hx-target="#contact-1" hx-swap="outerHTML">Edit</button>
</div>

When the user clicks "Edit," the server returns an inline form:

<form id="contact-1" hx-put="/contacts/1" hx-target="this" hx-swap="outerHTML">
    <input name="name" value="Jane Smith">
    <input name="email" value="[email protected]">
    <button type="submit">Save</button>
    <button hx-get="/contacts/1" hx-target="#contact-1" hx-swap="outerHTML">Cancel</button>
</form>

On save, the server validates the input and returns the updated display view. The entire edit-save cycle requires no client-side JavaScript, no state management, and no serialization logic. Your server-side framework handles everything it is already good at.

When HTMX Shines

HTMX is particularly well-suited for several categories of applications:

Content-driven sites with interactive elements. Blogs, dashboards, admin panels, and e-commerce sites benefit enormously. These applications are fundamentally about displaying and manipulating server-side data, which is exactly what HTMX streamlines.

CRUD applications. If your app is primarily about creating, reading, updating, and deleting records, HTMX removes an enormous amount of accidental complexity. You do not need a JSON API, a client-side data layer, and a rendering framework just to edit a row in a table.

Progressive enhancement of existing server-rendered apps. If you already have a Django, Rails, Laravel, Spring, or Express application, HTMX lets you add dynamic behavior incrementally without rewriting your frontend.

Small teams and solo developers. HTMX dramatically reduces the surface area you need to maintain. One language on the server, HTML on the client, and no build pipeline to debug at midnight.

Patterns and Best Practices

Use hx-indicator for Loading States

<button hx-get="/report" hx-target="#report-area" hx-indicator="#spinner">
    Generate Report
</button>
<span id="spinner" class="htmx-indicator">Loading...</span>

HTMX automatically toggles the htmx-request class on the indicator element during requests. Add a CSS rule to show or hide it.

Use hx-boost for Seamless Navigation

<body hx-boost="true">
    <a href="/about">About</a>
    <a href="/contact">Contact</a>
</body>

With hx-boost, regular links and forms are automatically converted to AJAX requests that swap the body content. Your site feels like a single-page application with zero code changes.

Return Partial HTML From the Server

Structure your server to return full pages for direct requests and partial HTML fragments for HTMX requests. Most server frameworks make this easy by checking the HX-Request header:

# Django example
def contact_list(request):
    contacts = Contact.objects.all()
    template = "contacts/_list.html" if request.headers.get("HX-Request") else "contacts/list.html"
    return render(request, template, {"contacts": contacts})

Use hx-push-url for Clean Browser History

<a hx-get="/page/2" hx-target="#content" hx-push-url="true">Next Page</a>

This updates the browser's URL bar and history, so back and forward buttons work as expected.

When HTMX Might Not Be the Right Choice

HTMX is not a universal replacement for JavaScript frameworks. There are legitimate cases where a client-side framework makes more sense:

  • Highly interactive, real-time collaborative apps like Figma or Google Docs require complex client-side state synchronization that goes beyond what hypermedia can elegantly handle.
  • Offline-first applications need client-side data persistence and sync logic that fundamentally cannot live on the server.
  • Rich data visualizations with complex client-side interactions (dragging, zooming, real-time chart updates) often need specialized JavaScript libraries and tighter client-side control.

For the vast majority of web applications, however, HTMX provides more than enough interactivity while keeping the architecture dramatically simpler.

The Ecosystem Around HTMX

Several companion tools extend HTMX for specific needs:

  • Hyperscript (_hyperscript) is a companion scripting language for lightweight client-side logic like toggling classes or simple animations.
  • idiomorph provides a morphing swap strategy that intelligently merges DOM changes, useful for preserving form state during updates.
  • Server-side libraries exist for Django (django-htmx), Rails (htmx-rails), Spring Boot, Go (templ), and many other frameworks, offering helpers for detecting HTMX requests and sending response headers.

FAQ

Does HTMX work with my existing backend framework?

Yes. HTMX is backend-agnostic. It works with any framework that can return HTML over HTTP — Django, Rails, Laravel, Express, Flask, ASP.NET, Spring Boot, Go, Phoenix, and anything else. No special server-side setup is required.

Is HTMX production-ready?

Absolutely. HTMX (and its predecessor, intercooler.js) has been used in production applications for years. It has a stable API, thorough documentation, and an active community. Companies of all sizes use it in production.

Can I use HTMX with existing JavaScript libraries?

Yes. HTMX plays well with other libraries. You can use it alongside Alpine.js for lightweight client-side reactivity, or integrate it with any JavaScript you already have. HTMX fires events at every stage of the request lifecycle that you can hook into with vanilla JavaScript.

How does HTMX handle SEO?

Since HTMX applications are server-rendered by default, they are inherently SEO-friendly. Search engines see fully rendered HTML. With hx-boost, even your AJAX-powered navigation degrades gracefully to standard page loads if JavaScript is disabled.

Does using HTMX mean I write zero JavaScript?

Not necessarily, but you will write dramatically less. Most HTMX applications need little to no custom JavaScript. For cases where you do need client-side logic — a date picker, a drag-and-drop interaction, a complex animation — you can write plain JavaScript or use a small library. HTMX does not lock you out of JavaScript; it simply removes the need for it in the majority of cases.

How does HTMX compare to frameworks like React or Vue in performance?

HTMX trades client-side rendering speed for simplicity and smaller bundle sizes. Each interaction involves a server round-trip, which adds latency compared to purely client-side updates. However, the total page weight is significantly smaller (14KB vs. hundreds of KB for a typical React app), initial page loads are faster, and for most applications the server response time is imperceptible to users. The net result is often a faster real-world experience despite the architectural difference.

Final Thoughts

HTMX is not about going backward. It is about recognizing that the web platform already has a powerful, proven model for building interactive applications — hypermedia — and that a small library can unlock its full potential without the complexity tax of modern JavaScript frameworks. If you have been feeling the weight of your frontend toolchain, give HTMX a serious look. You might find that the simplicity is exactly what your project needs.

Related Articles