Experiences using Tailwind CSS

Tailwind CSS has gained a lot of popularity in the recent years, for many good reasons. There are a ton of interesting things that it brings to the table.

One thing that I personally found interesting is that a lot of that popularity seems to come from backend developers, who almost by definition, don't write a lot of code on the frontend. As someone who also subscribes to that definition (at least to some extent), I found that bit quite intriguing. Developing code that's visible to the end-user has always been a bit of an Achilles' heel for me. So the thought of solving that problem was honestly quite exciting.

So, over the last few evenings and weekends, I rewrote the styling for this site using Tailwind, mostly to figure out what I can do with it. This post describes my experience with Tailwind so far.


Before we begin, it would help to establish a little bit of context. As I wrote earlier, my core technical competency is backend and infrastructure/devops software development. I have written frontend code in the past, but it was not where I spent most of my time. In the past whenever I had to kick-start a project, my first thought was to use either Bootstrap or Bulma. More often than not, the final result looked as if it was "engineered" and not "designed" (which was not the fault of the framework but rather a consequence of my limited design skills). It wouldn't be an exaggeration to say that I could identify with the following gif.

Backend Developer using CSS

Usually when I want to learn something new I like to read a book or a few blog posts to get up to speed. In this case I chose to dive heads first. I picked my personal website (the thing you're reading right now) as a playground and decided to rewrite the styling using Tailwind.

Making Tailwind work with Zola

This site is built using Zola and deployed on Netlify as a static site. I don't use a third-party theme, which means that all the HTML code on this site is under my control.

The first step was to install Tailwind. I ran npm install tailwindcss on the console and had that out of the way.

The next step was to initialize Tailwind, which is done using npx tailwindcss init. Running this command writes a tailwind.config.js file in the project root. I had to adjust the content key to point to the directory where my Zola template files live, so that the Tailwind CLI can look at what CSS classes the templates are using, and therefore should be included in the final CSS file served to the browser. I also had to install the @tailwindcss/typography plugin to make sure that the Markdown content which is rendered to HTML (by Zola) has good typographic defaults. The final tailwind.config.js looks like this:

/** @type {import('tailwindcss').Config} */

module.exports = {
    content: ["./templates/**/*.html"],
    theme: {
        extend: {},
    plugins: [

Next, I created a main.css file in the project root with the following contents:

@tailwind base;
@tailwind components;
@tailwind utilities;

And then I ran the command tailwindcss -i ./main.css -o ./static/main.css --watch --minify, and let it run in a separate terminal window. This command watches main.css and all the *.html template files for changes and recompiles (and minifies) the final CSS file to be included in the source code. The output is written to static/main.css which is served as the final result using a <link> tag.

For simplicity, I checked static/main.css into version control. The alternative would have been to generate it at build time in Netlify but that would have introduced additional complexity which I didn't want.

What I like

Overall, there is a lot to like about Tailwind. My experience has been so positive that I see myself reaching out for Tailwind before any other CSS framework in the near future. In this section I'll write about the two things that jumped out the most.

The first was how quick and easy Tailwind made it for me to get things in to a working state. Adjusting things using CSS has always been an issue for me. Frameworks like Bootstrap helped, but the moment something was out of scope of the framework (eg. modifying the appearance when the cursor is hovering over an element), I had to resort to searching on Google and copy/pasting code without having much of an understanding of what it was doing.

With Tailwind, I can set things in place really quickly. What helps me is to think of a page as a collection of components that are mostly independent of each other. This way, it's possible to define them individually, including thinking about how they should look like in responsive contexts. The "Flexbox & Grid" utility classes are especially helpful here.

The second thing that jumped out to me is how easy it is to make things look nice. I know that "nice" is a subjective word; maybe non-ugly is a better word? In any case, my experience has been that Tailwind generally makes things look nice by default. And, there is a vast collection of utility classes that lets you control the look and feel of essentially everything on the page. It's easy to control spacing using margins and paddings, control how text looks like, what colors are used (both for the main content and the background), transitions, and so much more. The number of utility classes is really enormous and I think I've barely scratched the surface so far. But my impression so far is that if you can think it, you can build it.

What I don't like

There's actually not much that I don't like. Regardless, to balance things out, I tried hard to think about it and was able to come up with two.

The first one is that the HTML code is not as clean as I would like. It's OK for a personal website like this where I'd like to keep the appearance simple. However, as the design gets more intricate, the number of CSS classes also explodes. Tailwind authors suggest using partials or components to solve this problem. I can absolutely agree. I'd probably even go one step further and say that without partials (or components) it's quickly going to go out of hand. So if you're using Tailwind, keep it in mind that at some point, you'll have to create those abstractions.

The second thing that I don't like know what to think of yet is the culture of copy/paste components that has cropped up in the ecosystem. There are a lot of Tailwind UI component libraries out there, Tailwind UI, Preline, Flowbite being the most popular ones. The usage instructions for all these libraries is "here is the HTML code, copy and paste it in to your project". In one of the side projects I've been using Tailwind UI components. The components themselves are extremely well done, which also means that the number of CSS classes is high. That in turn means that if you don't make some time upfront to go through the code and understand what those classes are doing, you might end up missing context. Traditionally, when you use a library, the library puts an abstraction between you and the underlying code (eg. btn instead of rounded bg-indigo-600 px-2 py-1 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600). Without any such abstraction, you just have to invest some time upfront to understand what each of those 13 classes are there for.


Overall, I've come to really like Tailwind. In my experience, it's an incredibly powerful tool that allows someone like me (with a technical skillset that has traditionally not focused on the frontend) to quickly build user-facing websites. This lets me work on the entire stack instead of being limited to just the backend. It's also honestly a lot of fun to work with. I love the instant feedback of applying a utility class and see the appearance change instantly. I can definitely see myself using it more and more in the future.