Django project - Part 4 HTMX, TailwindCSS and AlpineJS
Pedro Campos
Posted on November 29, 2024
Introduction
Now is the fun part, add HTMX, TailwindCSS, AlpineJS and change the home page to test the three libs.
The source code from this part
Tailwind
We are going to install the Tailwind through the container instance and then add the generated the json files to the Dockerfile, so it will be installed on the next build. This is made only once.
# install npm on image
RUN apk add --no-cache npm
Enter on the container to install Taiwind. let's add a just command to help in the future
justfile:
...
# Enter in the container shell
shell:
docker compose run --rm web sh
Execute the command
$ just shell
Enter on the container to install Taiwind. let's add a just command to help in the future
justfile:
# npm install -D tailwindcss
# npx tailwindcss init
That will create 3 files: package.json, package-lock.json and tailwind.config.js. Let's add them to the Dockerfile and rebuild the container, except the tailwind.config.js, which will be added with the rest of the code.
...
# install npm on image
RUN apk add --no-cache npm
# tailwind stuff
COPY package*.json ./
# use the json to install the Tailwind
RUN npm install
...
Create the file palindrome/static/css/input.css
@tailwind base;
@tailwind components;
@tailwind utilities;
and config the tailwind.config.js:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./palindrome/templates/**/*.{html,js}",
"./palindrome/static/**/*.{html,js}",
],
theme: {
extend: {},
},
plugins: [],
}
Add STATICFILES_DIRS to the settings.py to reflect the custom directory.
...
STATICFILES_DIRS = [BASE_DIR / 'palindrome/static']
Now we need to add the tailwind start on the start script, on docker/dev/start:
# -i the input.css for some tailwind directives or pure css, it will be added to the -o output.css in the
# tailwind processing, --watch=always is the hot reload.
echo "Starting tailwindcss watcher"
exec npx tailwindcss -i ./palindrome/static/css/input.css -o ./palindrome/static/css/output.css --watch=always &
You can add a tailwind tag to a header, in the palindrome/templates/base/home.html, to test the configuration:
<head>
...
<!-- Tailwind output file -->
<link
href="{% static 'css/output.css' %}"
rel="stylesheet">
...
</head>
...
<h1>Simple Header</h1>
<h1 class="text-3xl font-bold underline p-10">Simple Tailwind header</h1>
<hr>
...
AlpineJS
AlpineJS it's very simple, just download the lib and add to the page.
Go to the alpine.dev, download the lib cdn.mim.js
in the palindrome/static/css and change the name to alpine.min.js
. Should be something like this:
$ wget https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js
$ mv cdn.min.js alpine.min.js
Add to the home header and write a test code.
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta
name="viewport"
content="width=device-width, initial-scale=1.0">
<!-- Tailwind output file -->
<link
href="{% static 'css/output.css' %}"
rel="stylesheet">
<script
src="{% static 'js/alpine.min.js' %}"
defer></script>
<title>Title</title>
</head>
<body>
<h1>Simple Header</h1>
<h1 class="text-3xl font-bold underline p-10">Simple Tailwind header</h1>
<hr>
<h1 class="text-3xl font-bold underline pt-10 px-10">Simple AlpineJS counter</h1>
<div x-data="{ count: 0 }"
class="text-3xl font-bold underline pb-10 px-10">
<button x-on:click="count++">Increment</button>
<span x-text="count"></span>
</div>
<hr>
</body>
</html>
Now you have an increment button to test the Alpine configuration
HTMX
Almost as easy as the AlpineJS, but with a little more work.
Download the HTMX lib from HTMX website in the palindrome/static/js folder:
$ wget https://unpkg.com/browse/htmx.org@2.0.3/dist/htmx.min.js
Install an extension for django, the django-htmx, it has a Middleware that provides a request.htmx
, which in used in htmx partial views.
Create a View on the base/view.py
to respond to the HTMX call from the browser.
from django.http import HttpResponse
...
def htmx(request):
"""
A simple htmx view that return a partial html.
"""
return HttpResponse('<span id="click-test">HTMX is working</span>')
Add the View in the url.py
from django.urls import path
from palindrome.base.views import HomeView, htmx
app_name = 'base'
urlpatterns = [
path('', HomeView.as_view(), name='home'),
path('htmx/', htmx, name='htmx'),
]
Create a HTMX call from the home.html.
{% load static %}
<html lang="en">
<head>
...
<script
src="{% static 'js/htmx.min.js' %}"
defer></script>
<title>Title</title>
</head>
<body>
...
<hr>
<h1 class="text-3xl font-bold underline pt-10 px-10">Simple HTMX</h1>
<div class="flex flex-row">
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold
py-2 px-4 mb-10 mx-10 rounded w-fit"
hx-get="{% url 'base:htmx' %}"
hx-trigger="click"
hx-target="#click-test"
hx-swap="outerHTML"
>
Click Me!
</button>
<span id="click-test"></span>
</div>
</body>
</html>
Wraping up
Add /node_modules/
to the .gitignore
.
prepare for commit:
$ just format
$ git add .
$ git commit -m 'nice description'
Posted on November 29, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.