Contents
In brief
htmx 4.0 is a major step for apps that drive interactivity from markup instead of a thick client script. Internally, requests use fetch() instead of XMLHttpRequest; attributes no longer inherit to descendants unless you opt in with :inherited; morphing swaps (innerMorph / outerMorph) ship built-in; and <hx-partial> lets one response update several targets. Docs still open with a working example in a few lines of HTML—easy to judge if the approach fits.
What happened
Familiar hx-get / hx-post and swap targets still feel like htmx, but three decisions change upgrades. The biggest is inheritance: in 2.x a parent attribute often applied to children “like CSS”; in 4.x that only happens with :inherited. Classic footgun—hx-confirm or CSRF headers on a wrapper—silently stop reaching a child hx-delete without the suffix. The team ships npx [email protected] upgrade-check over templates plus a 2.x compatibility extension for gradual migration.
Moving to fetch() simplifies extensions (streaming, downloads) and drops old htmx:xhr:* events. Event names follow htmx:phase:action (for example htmx:before:request). History no longer snapshots the DOM into localStorage by default: back navigation re-fetches and swaps—fewer surprises from third-party script mutations.
For markup authors, morph swaps merge HTML into the live DOM (focus, field values, media state), and <hx-partial hx-target="…"> makes multi-target updates explicit in the response—clearer than out-of-band swaps alone.
Also noted briefly in Frontend Focus #756: Firefox 155 with a larger CSS haul (attr() more widely, progress(), alpha()) and the final removal of Manifest V2 extensions from the Chrome Web Store (including uBlock Origin). Surrounding news for the week—not the htmx story.
Why it matters
htmx sells server-driven UI from HTML. Implicit inheritance was powerful and confusing: editing a parent could change deep button behavior without an obvious local cue. Explicit :inherited makes templates readable at the cost of migration work. Morph and <hx-partial> cover common “rich screen” pains without standing up a full SPA layer: keep local state across updates, and touch a list and a counter in one response.
Product detail matters too: npm latest stays on 2.x until early 2027; the 4.x line is next, so unversioned CDNs do not force-upgrade. You can plan the move instead of discovering it by accident.
In practice
- Before switching versions, run
upgrade-checkon HTML/templates: it flags missing:inherited, old event names, and removed attributes. - Audit parent
hx-headers,hx-confirm, andhx-targetabove elements that issuehx-*requests—those almost always need:inherited. - Where focus and inputs matter, try
hx-swap="innerMorph"orouterMorphinstead of a full node replace; stableids help the morph algorithm. - Prefer
<hx-partial>with an explicithx-targetwhen one server response should update several regions—easier to maintain than a pile of out-of-band blocks. - For a soft landing, use the 2.x compatibility extension; in production, pin the script version instead of a bare CDN
latest.
Takeaway
htmx 4.0 doubles down on “behavior in markup”: modern requests via fetch(), honest attribute inheritance, morph swaps out of the box, and explicit multi-updates with <hx-partial>. Migrate on purpose—with the checker and template tests—rather than waiting for latest to flip someday.

