htmx: POST request

Join the AI Workshop to learn more about AI and how it can be applied to web development. Next cohort February 1st, 2026

The AI-first Web Development BOOTCAMP cohort starts February 24th, 2026. 10 weeks of intensive training and hands-on projects.


We previously saw how to use hx-get to do a GET request.

POST requests are similar, but using hx-post:

<button hx-post="/data" 
        hx-swap="innerHTML" 
        hx-target="#data">
  Load fresh data
</button>

<div id="data"></div>

If /data returns the same data as the GET request, this works in the same way.

But conceptually POST requests are used to send data to the endpoint.

This is done using forms.

If the element issuing the POST is inside a form, or is a form, all the input fields are sent to the endpoint as form data.

You can configure this behavior by filtering out some fields using hx-params and including other input fields using hx-include.

Typically you have a form like this:

<form
  hx-post="/projects"
  hx-target="#result">
  <input name="name" />
  <button type="submit">Add</button>
</form>

This is equivalent to:

<form>
  <input name="name" />
  <button 
    type="submit" 
    hx-post="/projects"
    hx-target="#result">
    Add
  </button>
</form>

Both work in the same way, htmx posts to /projects the data of the form, which in this case means the name input field value.

Note that if you use validation in a form, for example setting a field as required, the request will not be sent if validation fails.

Server-side, for example using Astro, you can get this data using Astro.request.formData():

---
export const partial = true

if (Astro.request.method === 'POST') {
  const formData = await Astro.request.formData()
  //this prints the form data to the console
  console.log(formData)
  
  //FormData { [Symbol(state)]: [ { name: 'name', value: 'my project name' } ] }
}
---

<p>project created</p>

Note that you must configure Astro to be server-rendered in astro.config.mjs:

import { defineConfig } from 'astro/config'

// https://astro.build/config
export default defineConfig({ 
+  output: 'server' 
})

Lessons in this unit:

0: Introduction
1: Why htmx
2: The core idea of htmx
3: Installing htmx
4: Doing a GET request
5: Swap
6: ▶︎ POST request
7: Targets
8: Loading indicator
9: Confirming actions, and prompts
10: Triggers
11: Request headers
12: Response headers
13: Events
14: Redirect after request
15: Send files using htmx.ajax()
16: Perform something on page load
17: Conditionally hide HTML elements based on HTMX request status
18: htmx + Alpine template tag
19: htmx, include hidden input fields outside of a form
20: htmx trigger request via JS event