04 March 2021
Tailwind CSS tutorial. A very hands-on approach to styling web applications
In the world of CSS frameworks, the battle for the best approach to styling web applications continues. Some choose CSS modules with SCSS or not, others prefer CSS in JS, and still, others simply install Material Design. There are many possibilities and depending on the needs, everyone will surely find something for themselves. In this article, however, I would like to focus on a solution that is completely different from those mentioned earlier. I’m talking about a framework recently gaining publicity – Tailwind CSS.
What is the Tailwind CSS framework?
Tailwind CSS doesn’t provide ready-made building blocks for your layouts like Bootstrap or Material Design but also does not focus on writing everything manually offering only syntactic sugar.
The creators themselves refer to it as “utility first” because what you mainly get in it is a set of existing classes that control individual aspects of the appearance and behaviour of your application elements.
Do you remember
invisible from Bootstrap? Then imagine Tailwind CSS only consists of this.
Another brick in the app – using Tailwind CSS
As I already mentioned, styling an application in Tailwind CSS is based on a set of classes which are modifying one or two CSS attribute each. Each element will have a lot of such classes assigned to it. This may seem crazy at first, but it works pretty well in practice.
Paradoxically, I’ve noticed that people who know CSS very well have the most difficulties with migrating to Tailwind CSS. Such developers may get discouraged when they have to check what class they should use to get the desired effect. After all, they could get the same result in a blink of an eye by writing CSS attributes manually, which they know perfectly well.
From my own experience, however, I will say that it is worth making this mental shift, because after learning a few rules governing the naming of classes in Tailwind CSS, your work will significantly speed up, and styling the application may turn out to be faster than using traditional CSS.
Let’s see how it looks in practice:
You have several classes used in this example. Leks check them one-by-one:
bg-green-300– this class sets a green background (this the bg prefix). The value 300 in the name is just the shade number.
border-green-600– it’s similar to the previous class but it sets the elements borders colour to a slightly darker green.
border-b– this class does nothing more than set the border to be visible only at the bottom (“b” stands for “bottom”)
m-4those two classes make the margin and padding the size of 4 units. In Tailwind CSS, this is equivalent to 16px.
rounded– finally, this sets the rounded corners for the element.
With all those classes the final effect will look like this:
If you don’t like the round corners, you can always adjust them. The rounded class has many varieties, such as
rounder-lg, that give the element corners a smaller or larger radius of rounding, respectively. It is also possible to round off only the selected corners.
Also, as you can see, it is impossible to describe all CSS classes and their varieties here. Tailwind CSS supports all popular CSS attributes and has many CSS classes to handle each of them. Shadows, borders, grids, flexboxes, colours and fonts – all of this is well supported. If you are interested, I encourage you to explore the Tailwind CSS documentation.
Don't like green? Then maybe cyan, red, or yellow?
What you saw above are the easiest ways to use Tailwind CSS classes. However, styling modern applications is more than just static appearance. Views must be responsive and must change according to the width of the device screen. Elements must also often react to mouse movement and, for example, highlight when hovering over them with the cursor.
All such responsiveness and different states of various elements are often the weakest elements of many low-level CSS frameworks. Not that the pure CSS was any better (writing media queries can be a nightmare) but usually, even in frameworks, these syntaxes aren’t exactly elegant.
What will the future bring for Frontend technologies?
You don’t need a crystal ball to predict that. 🔮 Check out our “State of Frontend” report based on a worldwide survey amongst 4500 developers.
However, Tailwind CSS is different. Here you operate on classes and if, for example, you want a class to be active only when the user hovers the cursor over the button, it’s enough to precede such class with the prefix of the CSS pseudoselector, e.g. hover:
The above example shows how the hover prefix was used to change the background of an element. Of course, Tailwind CSS supports other pseudo selectors as well. When it comes to more complex cases from the day-to-day battlefield, Tailwind CSS also tries to help. For example, you can very easily change the styles of the descendants of the selected element.
For this purpose, you just use the
group class in the element that is to be hovered over and the
group-hover prefix in the descendant:
If you begin to worry about the increasing length of class attributes then please remain calm. We will try to remedy this a bit later.
For now, let’s talk about responsiveness
It just so happens that handling responsiveness in Tailwind CSS is also fabulously simple. If you want some classes to be active for a given view, you precede them with a prefix denoting a specific screen size, e.g. ‘sm’ for larger phones,
md for tablets and
lg for monitors. The class without prefix will then only be used for the smallest screens.
In this example, you have created a block – the larger the screen on which you display it, the larger its margin. Of course, nothing prevents you from adding more classes to an element at the same time, preceded by the screen size prefix or some pseudoselector. Different prefixes can also be concatenated to get classes like
Here you may ask yourself since Tailwind CSS supports most CSS attributes with dozens of classes and each class can be preceded by one or more prefixes, will my application not grow by several megabytes after adding this framework?
And that is a very good question. It turns out that Tailwind CSS doesn’t generate all possible combinations by default. Moreover, it has the tools to remove unused classes and thus further reduce the size of the resulting source code.
But to talk about it in detail, we need to explain how to install Tailwind CSS in your application and how it works first.
Do you wanna know...
How to create a Tailwind CSS app?
Tailwind CSS doesn’t work as a regular CSS library. This isn’t just a collection of styles that you include in our CSS. You also need to properly transpile your code using Tailwind classes to get working styles as a result.
While there are several ways to use Tailwind CSS, the recommended method is the PostCSS preprocessor and a dedicated plugin that will generate the styles you need. The aforementioned preprocessor works like other tools of this type, e.g. SCSS or LESS: it takes your code and with the help of appropriate logic transpiles it into pure CSS. PostCSS has the advantage of being fully extensible. You can write plugins for it and expand its capabilities depending on your needs. This is a situation similar to Babel or Eslint.
If you use PostCSS, the exact way to install Tailwind CSS in your project will really depend on the technology stack, you can easily find the right instruction for installing everything on the Internet. A lot is also covered in the excellent Tailwind CSS documentation.
For the purposes of this article, I will discuss how to install the CSS framework in question in projects generated with the popular Create React App starter. Assuming that the project itself has already been created, you can proceed to install the necessary libraries in the appropriate versions:
The problem with CRA is that this tool uses PostCSS internally and doesn’t allow to override its preprocessor configuration in any built-in way. However, this isn’t a hopeless situation because you can use CRACO, a tool for easily overwriting all CRA settings. So install CRACO in your project:
… and then we modify the commands in package.json so that your application launched with the help of this tool:
The next step is to create a settings file for CRACO that will define how PostCSS configuration should be overwritten. For this purpose, in the main folder of your application, create the craco.config.js file and put the following content inside:
In the code above we added two plugins to the PostCSS configuration. The first is your Tailwind CSS transpiler to generate all the classes you need, and the second is an autoprefixer that will ensure all CSS attributes will be generated in versions for all browsers you should support.
Now that we have PostCSS configured, it’s time to add the Tailwind settings file itself. The fastest way to do this is to generate it with the command:
After a while, the tailwind.config.js file will appear in the main folder of your project with the following content:
This configuration is empty for now, but you will have time to expand it a bit before the end of the article. Now as long as you only add to the
purge field the files in which you are going to use the Tailwind classes. You can use the glob expressions:
This setting allows Tailwind CSS to check in the indicated files which classes you actually used in your project and which of them should be added to the production build of our application. All others will be cut out, reducing the final size of your styles.
For this mechanism to work properly, however, you must remember one rule: you mustn’t dynamically concatenate class names anywhere in the code.
That is, instead of doing something like this:
…you should always use uncut names:
Finally, there is one thing left to do. You need to indicate where you want to include this framework in your application. And you can do it in two ways. Either by adding PostCSS understandable instructions in one of your CSS files:
…or import the all-in-one set into a JS/TS file:
The latter solution is preferable if your stack allows you to directly import CSS files to JS.
*Atomic by Blondie playing in the background*
A tailor-made framework
If you think Tailwind CSS may not be the best choice for you because you are afraid it will limit you in some way, you can sleep well. Since all Tailwind classes are generated during the build, you can easily modify them from the configuration file.
Let’s take a look at such adjustments of the breakpoints of a responsive layout:
With the above code, you have overwritten the default Tailwind breakpoints, i.e.
lg, etc., and created your own. From now on, in your application, you can start using such classes as
desktop:text-white, that are activated on the resolutions indicated in the configuration file. If you need to use classes that are active up to a given resolution or set some more advanced conditions, then everything is possible:
For more examples and instructions on how to expand the breakpoint list without overwriting the default ones, please visit the official documentation pages.
Another aspect of Tailwind CSS that many of you will want to customize is the availability of colours. The easiest way to do this is by creating a palette from ready-made sets of shades. For example, if you plan to use red and yellow and a few other primary colours, your palette could look like this:
Nothing prevents you from defining your own shades or naming the colours in a specific way:
After such a reconfiguration of Tailwind CSS, you can refer to defined shades in the code using classes such as
Ok, what if you want to further modify the content of Tailwind’s built-in classes? This is also possible and it is also done from the configuration file level. Let’s assume that according to your class
shadow-lg casts too soft shadows for your taste and you want to strengthen this effect a bit. You can do it very easily by modifying the appropriate field in the theme settings:
Note how we have overridden the styles only for the lg variant, and left the rest of the settings default, referring to the default theme. Of course, other classes can also be modified as shown.
One more thing! I’ve mentioned at the beginning of the article that by default Tailwind doesn’t generate all prefix and class combinations. For example, without changing the settings, you cannot use the
active:shadow class in your application, which should appear on the button when it is clicked (equivalent to
button:active). Tailwind simply doesn’t generate this class for the default settings. How to change it? Pretty straightforward. That’s why there is a
variants field in the configuration, to set additional prefix combinations that we need.
Your own little bricks
So far, you have only modified existing class sets. Tailwind, despite being a very universal tool, doesn’t have classes for absolutely all CSS attributes or cases of their use. Tailwind also doesn’t support e.g. CSS attributes which are not yet supported in all browsers. Can Tailwind help you to create your own classes? As it turns out – yes.
You can order Tailwind to generate single classes or whole sets of classes with different prefixes. This is done in a CSS file using the
@layers at-rule For example, Tailwind doesn’t support CSS filters, so if you want to display elements in shades of grey on your website, you can add the missing filter support in the following way:
Thanks to this, you can now combine your
filter-none classes with the hover and focus prefixes and thus, for example, make colourful pictures only when they are indicated by the cursor.
Generating classes works great. But in this form, it can be quite a chore to define if you want to do a whole range of classes (e.g. set a different filter power in the range from 0 to 100 in increments of 10). Do you have to write everything manually then? Fortunately, Tailwind comes to your aid here as well.
You can write your own utility plugin for this framework that will generate definitions for a whole range of styles.
To add such a plug, you have to go back to your configuration file and import a file in the
plugins field, where you will store your styles generator.
The second step is to write the generator itself that produces all the class descriptions you need. In my scenario, the content of filter.tailwind.js looks like this:
When you look at it, there is nothing complicated here. First, you add a class that turns off grayscale to the object, i.e.
.filter-none. Later in the loop, you add more classes from
.filter-grayscale-10 all the way to
.filter-grayscale-100. Finally, the prepared data is sent to the
addUtilities function, indicating in the second parameter that the created classes are to support hover prefixes and those related to responsiveness.
And that’s it. All 10 classes with variants with different prefixes are ready for use. As you can see, writing Tailwind plugins is super easy. However, before you start doing it, I suggest that you always check if there is any ready-made solution on the Internet. There are many open-source plugins that are just waiting to be used, such as webdna/tailwindcss-aspect-ratio, which I highly recommend.
Looking for a Frontend job? We've got some great tips here
There is one more thing that I promised to mention. How to deal with long, expanding class lists? In the end, sooner or later this will happen to you:
I used 11 classes to describe this button, and in fact, not much is going on here. And I didn’t even take care of the button responsiveness yet! It’s hard to think about what could happen with much more complicated web components.
Fortunately, Tailwind CSS has solutions for this. First, you can define in your CSS file a so-called Tailwind component that will collect several atomic classes and combine them into one more complex class. There are two at-rules used here:
If you don’t like creating components from ready-made classes, you can go back to writing plugins. Component plugins are just as easy to write as utility plugins, and they allow us to define new complex styles using CSS in JS.
Creating components has another advantage over using atomic classes directly in your HTML code. When debugging you can better see what part of the code you are looking at because there are more telling names. Therefore, as I practice the method, I always create components to make the application code more readable and easier to develop. Please compare those two buttons yourself:
Should you try out Tailwind CSS? Yeah!
Is it worth getting more interested in using Tailwind CSS? Definitely. I think this is a tool every web developer should have in their skills toolbox.
Even if you think that this framework is not suitable for creating large dedicated applications, it is worth knowing it for building quick prototypes, responsive design, interactive elements, large screens design, navigation bars etc. Once we learn its class nomenclature, including utility classes, Tailwind CSS will immediately speed up creating each project and allow you to focus on business values instead of the details of CSS styling. Among other CSS frameworks, Tailwind CSS really stands out with its ability to deliver business value quickly.
Nevertheless, I believe Tailwind CSS also has its place in big projects. Developers don’t need to come up with names for many classes and aren’t obliged to check if someone else created any utils anymore. When you use Tailwind, you get all the tools right away, including utility first classes, custom designs etc. Writing code with Tailwind CSS is really straightforward!
In addition, Tailwind also helps you use a defined colour palette and maintain consistent spacing in the layout. And as we know: the bigger the project, the more people in the team, the harder it is to keep such things in check. Therefore, I propose to give this framework a chance. It will help to maintain the high quality of the code, which is a value for both developers and business.
PS: I didn’t mention it before, but Tailwind CSS also gives your app a dark mode for free.