Introduction #
Tailwind CSS provides a CLI for creating a minified CSS file containing only the classes required by your web templates.
In this post we will look at combining a simple templ
web page with the Tailwind CSS Standalone CLI.
For more information on templ
see: https://templ.guide
Installation #
There are a couple of tools we will need to be installed, this post assumes you already have Go installed (the post was written using 1.20).
Templ
Install the templ
command using go install
.
go install github.com/a-h/templ/cmd/templ@v0.2.304
Tailwind CSS Standalone CLI
Install the tailwindcss
command by downloading the latest release.
https://github.com/tailwindlabs/tailwindcss/releases
Boilerplate #
We will start with a new go module.
$ mkdir templ-tailwind
$ cd templ-tailwind
$ go mod init github.com/joerdav/templ-tailwind
Templ #
First, let's create a very simple templ
template, that displays the current time.
For brevity I am going to put all the code in a single main
package.
// home.templ
package main
import "time"
templ home() {
<html>
<body class="bg-white">
<div class="relative isolate px-6 pt-14 lg:px-8">
<div class="text-center">
<h1 class="text-4xl font-bold tracking-tight text-gray-900 sm:text-6xl">
The current time is: { time.Now().Format(time.RFC3339) }
</h1>
</div>
</div>
</body>
</html>
}
This template is mostly Tailwind styling, and then in the <h1>
we print the current time.
Now, templ
requires a generation step, we can do this using templ generate
. For ease we can also hook into the go generate ./...
command by adding the following file.
// gen.go
package main
//go:generate templ generate
Now run go generate ./...
.
$ go generate ./...
home.templ complete in 23.683327ms
Generated code for 1 templates with 0 errors in 24.470467ms
We now have a generated home_templ.go
file.
.
├── gen.go
├── go.mod
├── go.sum
├── home.templ
└── home_templ.go
Serving the page #
We now need to serve this page up, we can use net/http
for this. templ
also provides a wrapper to create a http.Handler
from a templ.Component
, by doing templ.Handler(home())
.
// main.go
package main
import (
"log"
"net/http"
"github.com/a-h/templ"
)
func main() {
if err := run(); err != nil {
log.Fatal(err)
}
}
func run() error {
http.Handle("/", templ.Handler(home()))
return http.ListenAndServe("localhost:8080", nil)
}
Let's give it a run with go run .
, and we can see our page but with no styling!
Generate CSS #
Now we have our template we can get tailwindcss
to generate some styles for us. First, we need to initialise.
tailwindcss init
This will create a config file for us.
.
├── gen.go
├── go.mod
├── go.sum
├── home.templ
├── home_templ.go
├── main.go
└── tailwind.config.js
And we can create a folder for our static assets.
$ mkdir css
Tailwind requires us to specify where our HTML templates live. We will specify all templ
files in our project.
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [ "./*.templ" ],
theme: {
extend: {},
},
plugins: [],
}
Now let's generate our css:
$ tailwindcss -o css/styles.css --minify
This will create a css file that only contains the code we need for our website.
.
├── css
│ └── styles.css
├── gen.go
├── go.mod
├── go.sum
├── home.templ
├── home_templ.go
├── main.go
└── tailwind.config.js
We could even include this as a generate step.
// gen.go
package main
//go:generate templ generate
//go:generate tailwindcss -o css/styles.css --minify
Tie it all together #
Now we have our page and our css file, we just need to link it all together. We can host our css folder as part of our server using the embed
package. This way our app can be shipped as a single binary!
// main.go
package main
import (
"embed"
"log"
"net/http"
"github.com/a-h/templ"
)
//go:embed css
var FS embed.FS
func main() {
if err := run(); err != nil {
log.Fatal(err)
}
}
func run() error {
http.Handle("/", templ.Handler(home()))
http.Handle("/public/", http.StripPrefix("/public", http.FileServer(http.FS(FS))))
return http.ListenAndServe("localhost:8080", nil)
}
Finally, let's reference this from our template.
package main
import "time"
templ home() {
<html>
<head><link rel="stylesheet" href="/public/css/styles.css"/></head>
...
With a final go generate
and a go run .
, we should have a website with minimal css, distributed as a single binary.
All code for this can be found at https://github.com/joerdav/templ-tailwind