Notes on HTMX
Htmx is a library that allows access to modern browser features directly in html rather than javascript. Some of the key features include any element the ability to issue an HTTP request, any event can trigger requests and any element can be the target of an update request, rather than the full window.
I'm using a flask backend for this project. You can build your own flask backend in 5 minutes
Let's setup a few test cases. Include the htmx library using this tag. I'm using Flask, so it will go in the head of my layout.html template.
<script src="https://unpkg.com/htmx.org@1.2.1" integrity="sha384-t37OW0DbqgL50XZW+Tl8TLchxsPoxIJ7NQ/l4aSZIXZVJQAhyQvvkWZgL/SiY/jD" crossorigin="anonymous"></script>
On my index.html template, I'll add the html I'll be writing within "block content"
On my routes.py, I have to account for each post, so I have a catch-all called /htmx that returns an empty 200 response.
@app.route('/htmx', methods=['GET','POST','DELETE', 'PUT'])
def htmx():
return ("",200)
Let's take one of the delivered examples. On the index.html page, add the following
<p>Button Fade Out</p>
<style>
.fade-me-out.htmx-swapping {
opacity: 0;
transition: opacity 1s ease-out;
}
</style>
<button class="fade-me-out" hx-delete="/htmx" hx-swap="outerHTML swap:1s">
Fade Me Out
</button>
Save and run your flask app and give it a go.
Seems to work well. If you're having issues, check the browser console and your flask output to see if you're route is set up correctly.
Let's do a few more examples:
<div class="column has-text-centered is-6">
<div hx-get="/weather" hx-trigger="click">
Click me for the weather
</div>
</div>
This will post to /weather, so let's add that route. For now, I'll just hard code the weather, but in the future we could call the weather API
@app.route("/weather", methods=["GET"])
def weatherHtmx():
weather = "It's sunny and cold"
return weather
Restart the server and click the button for weather. It works!
Let's do another one and get the time every second. There's better ways to do this than hitting the server every second, but we're experimenting and having FUN!
<div hx-get="/time" hx-trigger="every 1s">
Fetching time
</div>
for this route you'll have to import datetime
from datetime import datetime
@app.route("/time", methods=["GET"])
def newsHtmx():
now = datetime.now().time()
return "The current time is %s" % now
Ok twist my arm, let's add a proper API call on the weather route.
For this, I'm using openweathermap.org. You can get an account for free.
We'll need to import json and requests, and install the requests package.
pipenv install requests
import json, requests
@app.route("/weather", methods=["GET"])
def weatherHtmx():
zip='90210'
r = requests.get('http://api.openweathermap.org/data/2.5/weather?zip=%s,us&appid=YOURAPIKEY' % zip)
data=r.json()
weather = data['weather'][0]['description']
return weather
This will pull from 90210... so always clear skys and sunny, right? That's not good enough.
One last thing, let's replace the weather button with an input field to allow the user to enter a zipcode.
<input type="number" name="zip" placeholder="Zip Code"
hx-get="/weather" hx-target="#weather-results" />
<div id="weather-results"></div>
Then modify the route to grab the query string "zip" and do a try/catch in case they put in an invalid zipcode.
@app.route("/weather", methods=["GET"])
def weatherHtmx():
zip=request.args.get('zip')
try:
r = requests.get('http://api.openweathermap.org/data/2.5/weather?zip=%s,us&appid=YOURAPIKEY' % zip)
data=r.json()
weather = data['weather'][0]['description']
return weather
except:
return "no weather found... must be on the moon"
As you can see, htmx can do a lot with a on your front end with a very small amount of code.
[View this project on Gitlab] (gitlab.com/ajbot/htmx-flask)
AJ