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