HTMX on Cloudflare Pages
Using HTMX and Cloudflare Workers is a great way to sprinkle in some dynamic functionality into your Cloudflare Pages static site. Let's look at an example of handling a form submission.
Important! Before proceeding with adding HTMX to your Cloudflare Pages site, please make sure you've properly secured your site from XSS attacks. For a starter guide on this topic see our post Adding Security Headers on Cloudflare Pages
{{< divider "Cloudflare Wrangler Config" >}}
First step is to make sure you have Cloudflare Wrangler installed to be able to test your Cloudflare Worker locally (install directions can be found here).
Now let's create a 'wrangler.toml' file in the base directory of your project. This configuration file lets Wrangler know how to load your site.
# wrangler.toml
name = "example"
pages_build_output_dir = "public"
Explanation of Settings
- name: Can be anything, but best practice is to match the name of the app in Pages.
- pages_build_output_dir: The directory where your static site files live. If using Hugo that's "public".
Next make sure any Cloudflare Worker scripts you want to run are within a '/functions' folder within your site's root directory. Then run the below command to have Wrangler load your site. Default will for your site to be at http://localhost:8788.
npx wrangler pages dev
Note: This will live reload changes to your files in '/functions' but not in the 'pages_build_output_dir' path.
{{< divider "Using HTMX" >}}
As an example, let's create an email submission form using HTMX.
Firstly, add a form to the static page using the HTMX 'hx-post' directive. Here, we're also including the form's 'action' attribute as well to provide progressive enhancement.
<form action="/emailList" hx-post="/emailList">
<input type="email" name="email" placeholder="Enter your email">
<button class="button" type="submit">Get Notified</button>
</form>
On the static webpage that includes the email form include a HTML head script link to HTMX.
It's strongly advised to include a 'nonce' for this file to help guard against XSS attacks. See "Option 2" on Adding Security Headers on Cloudflare Pages
<head>
<script src="/path-to-HTMX/htmx.min.js"></script>
</head>
Lastly, create a new Cloudflare Worker at '/functions/emailList'.
Cloudflare Pages uses file based routing for the '/functions' folder. Meaning that Pages will automatically route requests to '/emailList' to your function '/functions/emailList'. Hence, why the HTML form above is posting to '/emailList'.
Below is an example of a Cloudflare Worker that expects to receive an email address form submission, stores in a database, and then returns a HTML snippet.
Reminder: Don't forget to sanitize user provided data before storing in your database. You'll thank me later :)
export async function onRequest(context) {
// Initialize variables.
const { request, env } = context
// Check if the request is an OPTIONS request.
if (request.method === 'OPTIONS') {
// Respond with headers that indicate which HTTP methods are allowed.
return new Response(null, {
headers: {
'Allow': 'POST, OPTIONS'
},
status: 204
})
}
// Check if the request is a POST request.
if (request.method === 'POST') {
// Get the form data.
const formData = await request.formData()
// Get the email from the form data.
const email = formData.get('email')
// Handle your form data here (e.g., send an email, store in a database, etc.)
console.log(`Email received: ${email}`)
// Return whatever content you want HTMX to replace the form with.
return new Response("Thank-you! We've saved your email address.", { status: 200 })
}
return new Response('Method not allowed', { status: 405 })
}
Note that in the above example we're handling both 'OPTIONS' and 'POST' methods. That's because HTMX will issue an 'OPTIONS' request prior to sending a 'POST' to make sure the server will accept a 'POST' method for the path.
Congratulations! You now have a dynamic form on your static Cloudflare Pages website.
Cheers 🥂