--- name: htmx-upgrade-from-htmx2 description: Use when helping a user upgrade or migrate their codebase from htmx 2.x to htmx 4.x. Covers attribute renames, event name changes, config updates, header changes, extension migration, and step-by-step upgrade workflow. --- # Upgrading from htmx 2 to htmx 4 htmx 4 is a ground-up rewrite. This guide covers the practical steps to migrate a codebase. ## Instructions for Claude When helping with an htmx 2 -> 4 upgrade: 1. Search the codebase for all htmx usage: `hx-` attributes, `data-hx-` attributes, `htmx:` event listeners, `htmx.` API calls, and server-side `HX-` header handling 2. Identify the scope: how many files, how complex the usage 3. Work through the steps below in order, making changes file by file 4. Run the shipped `upgrade-check` tool first (Step 0) to build the worklist 5. Pay special attention to the hx-disable/hx-ignore rename order (Step 1) 6. For attribute inheritance (Step 3), use codebase analysis to find likely-inherited attributes rather than blindly adding `:inherited` everywhere -- see the detailed instructions in that step 7. Check server-side code for header handling changes (often in middleware or base controllers) 8. Check for custom extensions -- these need a full rewrite ## Step 0: Run the Shipped Upgrade Checker htmx 4 ships a command-line checker. Run it first to scope the work. It prints clickable `file:line` references with a suggested fix for each hit. ```bash npx htmx.org@4.0.0 upgrade-check -- ./path/to/project # add file extensions the scanner does not know npx htmx.org@4.0.0 upgrade-check --ext .vue ./path/to/project ``` Pin the version to the htmx 4 release you are moving to. By default it scans `.html`, `.php`, `.js`, `.ts`, `.jinja`, `.jinja2`, `.j2`, `.erb` and `.hbs`. It flags removed attributes, old event names, inheritance patterns and extension changes. It does not rewrite anything, so work through the steps below with its output as the worklist. ## Step 1: Attribute Renames Search and replace across the codebase. **Order matters for hx-disable.** ``` # IMPORTANT: Do hx-disable FIRST (it means something different in htmx 2 vs 4) # In htmx 2, hx-disable stops htmx processing. In htmx 4, hx-ignore does that. hx-disable -> hx-ignore (htmx 2's "disable htmx processing") # Now safe to rename hx-disabled-elt hx-disabled-elt -> hx-disable (htmx 2's "disable elements during request") ``` ## Step 2: Remove Deleted Attributes | Find | Replace with | |-----------------------|-------------------------------------------------------------| | `hx-vars='...'` | `hx-vals='js:...'` (wrap value in `js:` prefix) | | `hx-params="..."` | Remove; use `htmx:config:request` event to filter params | | `hx-prompt="..."` | Load the `hx-prompt` extension (same syntax as htmx 2) | | `hx-ext="..."` | Remove (just including the extension script is enough) | | `hx-disinherit="..."` | Remove (inheritance is explicit by default) | | `hx-inherit="..."` | Remove (use `:inherited` modifier on individual attributes) | | `hx-request='...'` | `hx-config='...'`. Takes HCON, which accepts the old JSON | | `hx-history="false"` | Remove (history no longer uses localStorage) | ## Step 3: Update Attribute Inheritance In htmx 2, all attributes inherited implicitly from parent elements. In htmx 4, inheritance must be explicit using the `:inherited` modifier. ### How to find inherited attributes **Do not blindly add `:inherited` to everything.** Instead, analyze the codebase to find attributes that are actually being inherited. Look for this pattern: a parent element has an htmx attribute, and child/descendant elements rely on it without declaring it themselves. Common attributes that are frequently inherited: - **`hx-target`** -- very common. Look for a container with `hx-target` and multiple child elements with `hx-get`/`hx-post`/etc. that don't have their own `hx-target` - **`hx-include`** -- common in form-heavy UIs where a parent sets a shared include - **`hx-swap`** -- when a group of elements should all swap the same way - **`hx-boost`** -- typically set on a parent `