Interview Q&A · 42 questions · 23 answered publicly

htmx Interview Questions

Ordered by how often they're asked. Sign in free to see every answer, rate your confidence and run timed mock interviews.

  1. Most asked What is htmx?

    Summary

    htmx is a small, dependency-free JavaScript library that lets HTML attributes make HTTP requests and swap the HTML the server returns into the page. Any element can send a request, on any event, with any HTTP method, and update any part of the page, without writing JavaScript.

    Longer Answer

    You add attributes such as hx-get, hx-post, hx-target and hx-swap to ordinary HTML. When the element is triggered, htmx sends the request, receives an HTML fragment, and inserts it into the target. It works with any backend that returns HTML (Django, Flask, FastAPI, Rails, Laravel, Express, Go, ASP.NET) and needs no build step: one script tag.

    Code Example

    <button hx-get="/hello" hx-target="#greeting">Say hello</button>
    <div id="greeting"></div>
    

    Key Points

    • A JavaScript library driven by HTML attributes.
    • Server returns HTML, not JSON.
    • Any element, event, method and target.
    • Backend-agnostic, no build step.

    Deep dive: htmx Tutorial: htmx Introduction

    Permalink

  2. Most asked How does htmx compare with React or Vue?

    Summary

    React and Vue usually render HTML in the browser from JSON returned by an API, with state in JavaScript. htmx renders on the server and swaps HTML fragments, with state on the server. htmx means much less client code and no build step; frameworks are better for highly interactive, offline or multi-client UIs.

    Longer Answer

    With a SPA you write two applications: an API and a client that duplicates knowledge of how data is shown. With htmx you write one server-rendered app. The trade-off: every interaction that needs new data is a server round trip, and very rich client interactions (drag-and-drop editors, design tools) are awkward. Many products mix both: htmx pages with a framework "island" for one complex widget.

    Key Points

    • SPA: JSON + client rendering + client state.
    • htmx: HTML fragments + server state.
    • htmx: less code, no build.
    • Frameworks: rich, offline, multi-client UIs.

    Deep dive: htmx: Build Interactive Web Apps with HTML: Choosing htmx: Architecture Decisions

    Permalink

  3. Most asked What do hx-get, hx-post, hx-put, hx-patch and hx-delete do, and how are values sent?

    Summary

    Each issues a request with that HTTP method to the given URL when the element is triggered. An element sends its own value; a form sends its fields; a non-GET request inside a form also sends the form's fields. In htmx 2, GET and DELETE put values in the query string; POST, PUT and PATCH send them form-encoded in the body.

    Longer Answer

    Use methods as HTTP intends: GET for reads (never side effects), POST to create or run actions, PUT/PATCH to update, DELETE to remove. Extra values come from hx-include (other elements), hx-vals (JSON) and can be filtered with hx-params. Many servers ignore DELETE bodies, which is one reason htmx 2 moved DELETE values to the URL.

    Key Points

    • One attribute per HTTP method.
    • Element, form and enclosing-form values.
    • GET/DELETE: query string; others: body.
    • hx-include, hx-vals, hx-params add or filter values.

    Deep dive: htmx Tutorial: AJAX Requests

    Permalink

  4. Most asked What is hx-target, and what relative selectors does it support?

    Summary

    hx-target chooses where the response goes; by default it's the element that made the request. It takes a CSS selector or extended selectors: this, closest <sel>, next, next <sel>, previous, previous <sel> and find <sel>.

    Longer Answer

    Relative selectors let the same markup work for every item in a list. A delete button with hx-target="closest tr" removes its own row without unique ids. In htmx 2 hx-target is inherited, so it can sit once on a parent; in htmx 4 inheritance must be explicit with hx-target:inherited.

    Code Example

    <tr><td>Ada</td><td><button hx-delete="/contacts/1" hx-target="closest tr" hx-swap="outerHTML">Delete</button></td></tr>
    

    Key Points

    • Default: the requesting element.
    • Any CSS selector.
    • this, closest, next, previous, find.
    • Inherited in htmx 2.

    Deep dive: htmx Tutorial: Targets: hx-target

    Permalink

  5. Most asked What swap styles does hx-swap support?

    Summary

    innerHTML (the default, replace the target's content), outerHTML (replace the target), textContent, beforebegin, afterbegin, beforeend, afterend, delete (remove the target) and none (no swap, but response headers still apply). Modifiers add timing and scrolling: swap:300ms, settle:300ms, scroll:bottom, show:top, transition:true.

    Longer Answer

    Match the response to the swap: with beforeend the server returns only the new item; with outerHTML it returns the replacement element. The swap: delay keeps the old element with the htmx-swapping class so a CSS fade-out can run; transition:true uses the View Transitions API.

    Key Points

    • innerHTML default; outerHTML replaces the element.
    • before/after begin/end insert.
    • delete and none.
    • Modifiers for timing, scrolling, transitions.

    Deep dive: htmx Tutorial: Swapping: hx-swap

    Permalink

  6. Most asked How does hx-trigger work? Give examples of modifiers and special triggers.

    Summary

    hx-trigger names the event that sends the request (defaults: change for inputs, submit for forms, click otherwise). Modifiers: once, changed, delay:<t> (debounce), throttle:<t>, from:<selector>, target:<selector>, consume, queue. Special triggers: load, revealed, intersect, every <t>. Filters in brackets: keyup[key=='Enter'].

    Longer Answer

    Several triggers are comma-separated: hx-trigger="load, every 5s". Custom events work too, including events fired by the server through the HX-Trigger header, with from:body to listen anywhere on the page. Filters are JavaScript expressions, so they need htmx.config.allowEval (true by default).

    Code Example

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

    Key Points

    • Defaults per element type.
    • delay/throttle/changed/once/from.
    • load, revealed, intersect, every.
    • Event filters in brackets.

    Deep dive: htmx Tutorial: Triggers: hx-trigger

    Permalink

  7. Most asked How do you handle form validation errors with htmx?

    Summary

    Keep browser validation (required, type=email) for instant feedback, and always validate on the server. On errors, return the form with the user's values and messages, ideally with status 422. htmx 2 doesn't swap 4xx responses by default, so add a responseHandling rule that swaps 422, or use the response-targets extension (hx-target-422).

    Longer Answer

    A common shortcut is returning errors with 200 so htmx swaps them, but then monitoring and tests can't tell success from failure. Accessible error markup links the message with aria-describedby and marks the field aria-invalid. In htmx 4, 4xx/5xx responses are swapped by default, and hx-status gives per-code control.

    Code Example

    <meta name="htmx-config" content='{"responseHandling": [{"code": "204", "swap": false},
      {"code": "422", "swap": true}, {"code": "[23]..", "swap": true}, {"code": "[45]..", "swap": false, "error": true}]}'>
    

    Key Points

    • Browser validation plus server validation.
    • Return the form with values and messages.
    • 422 + responseHandling rule in htmx 2.
    • Accessible error markup.

    Deep dive: htmx: Build Interactive Web Apps with HTML: Forms the htmx Way

    Permalink

  8. Most asked What security risks are specific to htmx, and how do you mitigate them?

    Summary

    Any XSS becomes more dangerous because injected hx- attributes are activated by htmx (an injected hx-delete with hx-trigger="load" would run). Mitigate by escaping all output, wrapping user HTML in hx-disable, keeping selfRequestsOnly on, and considering allowScriptTags: false and allowEval: false with a strict CSP.

    Longer Answer

    Server rendering means the template engine is your XSS defence: never mark user content as safe. hx-disable stops htmx from processing any attributes inside an element. CSRF still applies because htmx requests carry cookies. Set historyCacheSize to 0 for sensitive pages so snapshots aren't kept in sessionStorage.

    Key Points

    • Escape output; injected hx- attributes run.
    • hx-disable around user HTML.
    • selfRequestsOnly, allowEval, allowScriptTags.
    • CSRF and history cache.

    Deep dive: htmx: Build Interactive Web Apps with HTML: Securing an htmx App

    Permalink

  9. Most asked What does 'hypermedia-driven application' mean?

    Summary

    An application where the server answers with hypermedia (HTML that includes the next possible actions as links, forms and htmx attributes) instead of raw data. The client doesn't need to know the application's rules; it renders what the server sends and follows the controls in it.

    Longer Answer

    This is how the original web worked, and it's the architecture REST was describing (hypermedia as the engine of application state). Single-page apps instead use JSON APIs and put rendering and much of the logic in the browser. htmx extends HTML's hypermedia controls so a hypermedia-driven app can be as interactive as most SPAs, while keeping state and rendering on the server.

    Key Points

    • Server sends HTML with the available actions.
    • Client renders and follows controls.
    • Logic and state stay on the server.
    • htmx makes hypermedia more capable.

    Deep dive: htmx: Build Interactive Web Apps with HTML: Why htmx? Hypermedia vs JSON APIs

    Permalink

  10. Most asked Explain the htmx request lifecycle.

    Summary

    An event triggers an element; htmx collects values and headers and sends the request; the server returns HTML; htmx swaps it into the target using the swap style; then it settles, processing htmx attributes in the new content. Events fire at each step (htmx:configRequest, beforeRequest, beforeSwap, afterSwap, afterSettle, afterRequest).

    Longer Answer

    Because new content is processed, the server's HTML can contain more hx- attributes and the interaction continues from there. Hooks at each step let you change parameters and headers (htmx:configRequest), cancel requests (htmx:beforeRequest), change whether or where to swap (htmx:beforeSwap), or initialise widgets (htmx:load).

    Key Points

    • Trigger → request → response → swap → settle.
    • New content is processed for hx- attributes.
    • Events at every step.
    • Hooks to modify or cancel.

    Deep dive: htmx Tutorial: How htmx Works

    Permalink

  11. Most asked What happens in htmx 2 when the server returns 204, 404 or 500?

    Summary

    None of them are swapped by default. 204 means 'nothing to swap'. 4xx and 5xx fire htmx:responseError and leave the page unchanged; a network failure fires htmx:sendError and a timeout fires htmx:timeout. htmx:afterRequest fires in every case with detail.successful.

    Longer Answer

    Without handling, failures are silent to the user. Add a global listener (or hx-on::after-request) that shows a message and keeps the user's input. Note the default timeout in htmx 2 is 0 (none): set htmx.config.timeout or hx-request='{"timeout": ...}'. Delete endpoints should return an empty 200, not 204, when the row should disappear.

    Key Points

    • 204, 4xx, 5xx aren't swapped by default.
    • responseError, sendError, timeout events.
    • afterRequest with detail.successful.
    • No default timeout in htmx 2.

    Deep dive: htmx: Build Interactive Web Apps with HTML: Loading States, Races and Failures

    Permalink

  12. Most asked How do you show loading indicators and prevent double submits?

    Summary

    During a request htmx adds the htmx-request class to the requesting element; elements with the htmx-indicator class inside it (or named by hx-indicator) become visible. hx-disabled-elt disables elements (for example find button) until the request finishes, and hx-sync controls overlapping requests.

    Longer Answer

    htmx injects default CSS: .htmx-indicator has opacity 0, and opacity 1 during requests. You can disable that with htmx.config.includeIndicatorStyles and style it yourself. For critical actions, make the server endpoint idempotent too (for example a unique form token), because disabled buttons don't stop retries or other tabs.

    Key Points

    • htmx-request class during requests.
    • htmx-indicator / hx-indicator.
    • hx-disabled-elt stops double clicks.
    • Idempotent endpoints for safety.

    Deep dive: htmx Tutorial: Loading Indicators

    Permalink

  13. Most asked How would you implement active search with htmx?

    Summary

    A search input with hx-get to the search endpoint, hx-trigger="input changed delay:300ms, search", hx-target on the results container (for example the tbody), hx-sync="this:replace", an indicator, and hx-replace-url to keep the query in the URL. The server returns only the matching rows (or an empty-state row).

    Longer Answer

    On the server it's a parameterised query with a LIMIT. The same URL should return the full page for normal visits (check HX-Request) so the search URL can be bookmarked. aria-live on the results helps screen-reader users.

    Key Points

    • Debounced trigger + changed.
    • Swap only the results.
    • hx-sync replace to avoid stale results.
    • hx-replace-url and full-page fallback.

    Deep dive: htmx Tutorial: Active Search

    Permalink

  14. Most asked What are out-of-band swaps?

    Summary

    Elements in a response with hx-swap-oob (and an id) are taken out of the response and swapped into the page elements with the same id, in addition to the main swap. This updates several places from one request, such as a new row plus a counter in the header.

    Longer Answer

    Values: true (outerHTML on the element with the same id), innerHTML, or a style with a selector such as beforeend:#notifications. Table rows sent out of band must be wrapped in a <template>, because the HTML parser drops a <tr> outside a table. In htmx 2 OOB swaps run before the main swap; in htmx 4 after.

    Code Example

    <li>New task</li>
    <span id="task-count" hx-swap-oob="true">8</span>
    

    Key Points

    • hx-swap-oob + id.
    • Several updates from one response.
    • Wrap table rows in <template>.
    • Order changes in htmx 4.

    Deep dive: htmx Tutorial: Out-of-Band Swaps

    Permalink

  15. Most asked How can the server trigger client-side events, and why is that useful?

    Summary

    With the HX-Trigger response header: a single event name, a comma-separated list, or JSON with details ({"showMessage": "Saved"}). The event fires on the triggering element and bubbles, so other elements listen with hx-trigger="myEvent from:body" and refresh themselves.

    Longer Answer

    It decouples components: an 'add task' endpoint doesn't need to know about every counter, badge and list that should update. htmx 2 also supports HX-Trigger-After-Swap and HX-Trigger-After-Settle (removed in htmx 4). Use lower-case, dash-separated event names if you listen with hx-on, because attribute names are lower-cased.

    Key Points

    • HX-Trigger response header.
    • Name list or JSON with details.
    • Listen with from:body.
    • Decouples parts of the page.

    Deep dive: htmx: Build Interactive Web Apps with HTML: Adding Contacts and Updating Several Places

    Permalink

  16. Most asked Which request headers does htmx send, and how are they used?

    Summary

    HX-Request: true on every htmx request; HX-Trigger (id of the triggered element), HX-Trigger-Name, HX-Target (target id), HX-Current-URL, HX-Boosted for boosted requests, HX-Prompt for hx-prompt answers, and HX-History-Restore-Request for history restores.

    Longer Answer

    The main use is choosing between a fragment and a full page for the same URL: render the partial when HX-Request is present (and HX-History-Restore-Request is not), otherwise the full page, and send Vary: HX-Request so caches keep the versions apart. HX-Trigger and HX-Target let one endpoint serve several widgets.

    Key Points

    • HX-Request identifies htmx.
    • Trigger, target and URL details.
    • HX-History-Restore-Request needs a full page.
    • Vary: HX-Request for caches.

    Deep dive: htmx Tutorial: The Server Side

    Permalink

  17. Most asked How do you make third-party widgets work in content loaded by htmx?

    Summary

    Initialise them in htmx.onLoad(callback) (the htmx:load event), which runs for the initial page and every piece of new content htmx adds. If your own JavaScript inserts HTML containing hx- attributes, call htmx.process(element) so htmx activates it.

    Longer Answer

    Code that runs only on DOMContentLoaded misses content swapped in later, which is a common bug after adding htmx or hx-boost. Make initialisation idempotent (mark processed elements) because content can be processed more than once, and clean up widgets in htmx:beforeCleanupElement if they hold timers or listeners.

    Key Points

    • htmx.onLoad for new content.
    • htmx.process for your own inserted HTML.
    • Idempotent initialisation.
    • Clean up when content is removed.

    Deep dive: htmx: Build Interactive Web Apps with HTML: htmx and JavaScript Together

    Permalink

  18. Most asked What does hx-boost do?

    Summary

    hx-boost="true" on a container upgrades its normal links and forms: htmx requests the same URL in the background, swaps the response's body into the current page, updates the title and pushes the URL. It's progressive enhancement: without JavaScript, links and forms still work normally.

    Longer Answer

    Navigation feels faster because the browser keeps the loaded CSS and scripts. Inherited hx-target, hx-select and hx-swap can narrow the swap to a main area. Watch out for scripts that expect a fresh page load each time; initialise them with htmx.onLoad. Only same-site links are boosted.

    Key Points

    • Upgrades links and forms to AJAX.
    • Swaps body, updates title, pushes URL.
    • Works without JavaScript.
    • Re-initialise scripts on htmx:load.

    Deep dive: htmx Tutorial: hx-boost, hx-push-url and History

    Permalink

  19. Most asked A user reloads a page whose URL was pushed by htmx and sees an unstyled fragment. What's wrong?

    Summary

    The endpoint returns the same fragment to every request. On reload the browser requests the URL directly, without HX-Request, and needs the full page. Check HX-Request (and HX-History-Restore-Request) to choose between the partial and the full page, and send Vary: HX-Request.

    Longer Answer

    In htmx 2, history restore after a cache miss sends HX-Request: true together with HX-History-Restore-Request: true, so treat the latter as a full-page request (or set htmx.config.historyRestoreAsHxRequest = false). Without Vary, browser or CDN caches can still mix up the two versions.

    Key Points

    • Direct visits need full pages.
    • Branch on HX-Request.
    • Handle HX-History-Restore-Request.
    • Vary: HX-Request.

    Deep dive: htmx: Build Interactive Web Apps with HTML: URLs, History and hx-boost

    Permalink

  20. Most asked How do you organise server templates for an htmx app?

    Summary

    Put each fragment htmx requests in its own partial template (or use template fragments to render a named block), include it from the full page, and pick partial vs page based on HX-Request. Keep handlers thin and markup in one place.

    Longer Answer

    Libraries help: django-htmx (request.htmx), django-template-partials, jinja2-fragments, htmx helpers for Laravel, Rails and ASP.NET. Avoid duplicating markup between the page template and the htmx handler; it drifts. Test endpoints both with and without the HX-Request header.

    Key Points

    • Partials or template fragments.
    • One source of markup.
    • Branch on HX-Request.
    • Test both response types.

    Deep dive: htmx: Build Interactive Web Apps with HTML: Organising the Server: Partials, Fragments and Headers

    Permalink

  21. Most asked How do you handle CSRF tokens with htmx?

    Summary

    Send the token as a header on every request: hx-headers='{"X-CSRFToken": "..."}' on <body> is inherited by all htmx requests, or add it in an htmx:configRequest listener. Use the header name your framework expects (Django X-CSRFToken, Laravel X-CSRF-TOKEN), plus SameSite cookies.

    Longer Answer

    htmx requests are same-origin requests that include cookies, so they are just as exposed to CSRF as normal forms; don't exempt them. Forms that contain the framework's hidden token field also work, because htmx sends form fields.

    Key Points

    • htmx requests carry cookies.
    • hx-headers on body or configRequest.
    • Framework-specific header names.
    • SameSite cookies too.

    Deep dive: htmx Tutorial: Security

    Permalink

  22. Most asked When would you not choose htmx?

    Summary

    When the UI changes constantly without the server (drawing tools, spreadsheets, drag-and-drop editors, games), must work offline, or must share a JSON API with mobile apps and the team is already strong in a SPA framework. Even then, htmx can serve the simpler parts of the product.

    Longer Answer

    htmx's strengths are server-owned data, forms, tables, search, dashboards and content pages, with small dependencies and no build step. A hybrid with framework islands for complex widgets is common. Base the decision on where state lives, how often the UI changes without the server, other clients and team skills.

    Key Points

    • Rich client-only interactions.
    • Offline-first apps.
    • Shared JSON API and SPA team.
    • Hybrids are normal.

    Deep dive: htmx Tutorial: When to Use htmx

    Permalink

  23. Most asked What changed in htmx 4?

    Summary

    htmx 4.0 (August 2026) switched from XMLHttpRequest to fetch() with streaming, made inheritance explicit (:inherited), swaps 4xx/5xx responses by default (except 204/304) with hx-status for control, renamed events to htmx:phase:action (htmx:after:request), renamed hx-disable to hx-ignore and hx-disabled-elt to hx-disable, removed history snapshots in storage, and added a 60-second default timeout and morph swaps.

    Longer Answer

    htmx 2 remains supported indefinitely and stays npm's latest until some point in early 2027, so upgrading is optional. The official upgrade checker (npx [email protected] upgrade-check) finds the attributes and events to change. Extensions are now loaded with a script tag, without hx-ext.

    Key Points

    • fetch() and streaming.
    • Explicit inheritance.
    • Error responses swapped; hx-status.
    • Renamed events and attributes.

    Deep dive: htmx Tutorial: Upgrading to htmx 4

    Permalink

  24. What is the difference between delay and throttle in hx-trigger?
  25. What is hx-sync, and when do you need it?
  26. How do you add htmx to a page?
  27. How do you send values from elements outside the requesting element?
  28. How do you implement infinite scroll with htmx?
  29. How do you build click-to-edit with htmx?
  30. Why might a deleted row not disappear in htmx, and how do you fix it?
  31. Which response headers can an htmx server send?
  32. Why shouldn't an htmx endpoint answer with a 302 redirect after a successful POST?
  33. What is hx-on, and when should you use it?
  34. What is the difference between hx-push-url and hx-replace-url?
  35. What is the difference between hx-disable and hx-disabled-elt in htmx 2?
  36. How do you implement real-time updates with htmx?
  37. How does attribute inheritance work in htmx 2, and what changes in htmx 4?
  38. How do you test an htmx application?
  39. What are htmx's JavaScript API functions you use most?
  40. What is hx-select, and when is it useful?
  41. How do you confirm destructive actions in htmx?
  42. Where did htmx come from?

Was this page helpful?