Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Inline Editing with hx-put

Welcome to the next lesson in our journey from React to HTMX. In our previous sessions, you've mastered fetching and displaying lists (hx-get) and adding new items to them (hx-post). These "Read" and "Create" operations are foundational. Today, we'll build on that by tackling the "Update" part of CRUD, a pattern that truly highlights the power and elegance of the hypermedia approach.

Our objective is to implement an inline "edit-in-place" feature. You're likely familiar with the React version of this: toggling an isEditing state variable, conditionally rendering either a display component or a controlled form component, handling the onChange for inputs, and managing the submission with an API call. With HTMX, we will achieve the same result by having the server orchestrate the UI swaps, moving the logic from the client to the backend.

The Hypermedia "Edit-in-Place" Flow

The core pattern for inline editing in HTMX is a two-step dance between the client and server. It's a clear, RESTful sequence that keeps the client simple and relies on the server to deliver the correct UI fragments at each stage.

  1. Requesting the Edit Form: The user clicks an "Edit" button next to an item. This triggers an hx-get request to a dedicated endpoint, like /items/:id/edit.
  2. Server Renders the Form: The server receives this request, fetches the data for that specific item, and renders an HTML partial of a <form> with the input fields pre-populated with the item's current data.
  3. Client Swaps in the Form: HTMX receives this form fragment and swaps it into the DOM, replacing the original item's display view. The user now sees an editable form where the static content used to be.
  4. Submitting the Update: The user modifies the data and submits the form. This triggers an hx-put request to an endpoint like /items/:id, sending the new data.
  5. Server Updates and Renders the View: The server processes the PUT request, updates the item in the database, and then renders an HTML partial of the item's updated display view.
  6. Client Swaps Back to View Mode: HTMX receives this updated display fragment and swaps it into the DOM, replacing the edit form. The user sees the updated item, and the cycle is complete.

This entire process occurs without a full page reload and without you needing to write complex client-side state management logic.

Step 1: From View to Form (hx-get)

Let's start with the first half of the pattern: clicking an item to replace it with an edit form. The Net Ninja channel provides an excellent walkthrough of this specific step.

HTMX Tutorial for Beginners #10 - Swapping Content (more practise)

This video covers how to trigger a request to fetch an edit form and swap it into the page.

First, watch the setup from the beginning. Focus on how hx-get is used to request a specific edit form and hx-target="closest li" tells HTMX to target the parent list item for the swap, rather than just the element that was clicked. Next, observe the server-side implementation from the Express route. The app.get('/books/edits/:id', ...) handler finds the specific book and prepares to render a template for it. See how a dedicated EJS template for the edit form is created from this segment. Notice that the form inputs are pre-populated with the data passed from the server. Finally, watch the server send the response and see the result in the browser from the final demo.

As the video demonstrates, the key is the combination of hx-get to fetch the form and hx-target with the closest modifier to ensure the entire item view is replaced by the incoming form fragment.

Step 2: From Form to View (hx-put)

Once the user has the edit form, they need to be able to save their changes. This is where hx-put comes in. This next video from the same series completes the pattern.

HTMX Tutorial for Beginners #11 - PUT Requests

This video shows how to handle the submission of the edit form to update the data and swap the UI back to its display state.

Watch how the hx-put attribute is added to the <form> tag from the beginning. This will send the form's data as a PUT request upon submission. Next, focus on the server-side app.put handler from this section. The code extracts the ID from the URL parameters and the updated title/author from req.body. It then finds the item in the data store and updates it. Pay close attention to the final client-side configuration from the attribute setup. This is crucial: hx-target="closest li" and hx-swap="outerHTML" are added to the form. This ensures that when the server responds with the updated item view, it replaces the entire list item, including the form. See the full pattern in action from the demo.

The critical insight here is the use of hx-swap="outerHTML". When the server sends back the updated <li>...</li> fragment, outerHTML replaces the entire existing <li> (which contains the form) with the new one. If we used the default innerHTML, we would incorrectly insert the new <li> inside the old one.

This animated GIF shows the inline edit pattern in a to-do list. Clicking the edit icon transforms the text into an input field. After editing and saving, the application updates the item seamlessly.

A Complete Example: Editing a Table Row

The official HTMX documentation provides a concise example of this pattern applied to a table row, which introduces a useful technique for handling forms within tables.

</> htmx ~ Examples ~ Edit Row

This resource demonstrates the full edit-in-place flow for a table row, which has special considerations compared to a list.

First, examine the HTML for a display row. Note the hx-get on the "Edit" button, which initiates the process. The tbody tag above it has hx-target="closest tr" and hx-swap="outerHTML", which establishes the swapping behavior for any HTMX request originating within it. Next, study the HTML for the editable row. This is the fragment the server sends back. Notice two key things: The "Save" button uses hx-put to send the update. It also uses hx-include="closest tr". This attribute is essential here. Since you cannot legally nest a <form> element inside a <tr>, hx-include tells HTMX to find the closest parent <tr> and include the values of all <input> elements within it as part of the PUT request. This is a clean solution to a common HTML constraint.

This hx-include attribute is a powerful tool that gives you flexibility in your markup structure, allowing you to create hypermedia-driven interactions even within the constraints of HTML specifications for elements like tables.

This image from the HTMX examples shows the server log during an edit-in-place action. A `GET` request retrieves the edit form, and a subsequent `PUT` request sends the updated data, with the server responding with HTML fragments at each step.

An Alternative: The Single-Fragment Approach

While the two-step GET/PUT process is the purest hypermedia pattern, another common approach borrows a small leaf from the SPA playbook to optimize for fewer network requests.

In this alternative, the server sends a single fragment that contains both the display view and the (initially hidden) edit form. A tiny bit of client-side JavaScript (often using a library like Alpine.js, which we'll cover later) is used to toggle the visibility between these two states.

htmx and Alpine.js: Build Interactive Web Apps Without Heavy JavaScript Frameworks

This article demonstrates the hybrid approach where a single fragment contains both view and edit states.

Read through the code for the Task Item partial (views/partials/task-item.ejs). You can find the relevant EJS template within <tf start="<div class="task-card priority-<%= task.priority %>"" end=" ">this code block. Notice the following: x-data="{ editing: false }": This is an Alpine.js attribute that initializes a local state variable editing to false. <div x-show="!editing">...</div>: The display view is only shown when editing is false. <div x-show="editing">...</div>: The edit form is only shown when editing is true. <button @click="editing = true" ...>Edit</button>: The "Edit" button doesn't make a server request. It simply toggles the editing state variable on the client, which hides the display view and shows the form. The hx-put on the form itself works exactly as we've already discussed. It sends the update and the server responds with a new version of this entire fragment, which replaces the old one and resets the editing state to false.

This pattern trades hypermedia purity for network efficiency. It avoids the GET request for the edit form, making the UI feel instantaneous. The trade-off is a slightly more complex HTML fragment and a dependency on a small client-side script. For your migration projects, you can choose the pattern that best fits the specific interaction's performance requirements.

Conclusion

You have now learned the core patterns for implementing the "Update" operation in a hypermedia-driven application. This is a significant step beyond simple data display and creation.

Key Takeaways:

  • The Two-Step Pattern: The fundamental inline edit flow consists of an hx-get to fetch a pre-filled edit form, followed by an hx-put to submit the changes.
  • Server-Rendered Partials: The server is responsible for rendering the correct HTML fragment at each step—first the form, then the updated view.
  • hx-put: This is the conventional verb for sending updates for an existing resource.
  • hx-swap="outerHTML": This swap strategy is crucial for replacing an entire component (like a list item or table row) with the updated version from the server.
  • hx-include: A valuable utility for including input values in a request when you cannot use a standard <form> wrapper, particularly useful within <table> structures.
  • Hybrid Approach: You can optimize by pre-loading the edit form in a hidden state and using minimal JavaScript to toggle its visibility, saving a network request.

In our next lesson, we will complete our tour of basic CRUD functionality by implementing the "Delete" operation. You'll find it's a straightforward application of the principles you've learned today, using hx-delete to remove items from your list.

Can't find a good explanation? Sign up and we'll make it for you

Sign up