Over the past few months, I've been using Tailwind for some WebApp projects not related to ExtJS. Tailwind is a framework very different from Bootstrap or similar products. In fact, it uses a utility-first approach where CSS classes are linked to functionalities rather than components.
How Tailwind CSS Works
To try to clarify the concept a bit, I'll use the same example from the official website.
Let's take this component:
Using a traditional approach, we would need to use code like this:
<div class="chat-notification">
<div class="chat-notification-logo-wrapper">
<img class="chat-notification-logo" src="/img/logo.svg" alt="ChitChat Logo">
</div>
<div class="chat-notification-content">
<h4 class="chat-notification-title">ChitChat</h4>
<p class="chat-notification-message">You have a new message!</p>
</div>
</div>
<style>
.chat-notification {
display: flex;
align-items: center;
max-width: 24rem;
margin: 0 auto;
padding: 1.5rem;
border-radius: 0.5rem;
background-color: #fff;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
.chat-notification-logo-wrapper {
flex-shrink: 0;
}
.chat-notification-logo {
height: 3rem;
width: 3rem;
}
.chat-notification-content {
margin-left: 1.5rem;
}
.chat-notification-title {
color: #1a202c;
font-size: 1.25rem;
line-height: 1.25;
}
.chat-notification-message {
color: #718096;
font-size: 1rem;
line-height: 1.5;
}
</style>
With Tailwind, however, something like this is enough:
<div class="p-6 max-w-sm mx-auto bg-white rounded-xl shadow-lg flex items-center space-x-4">
<div class="shrink-0">
<img class="size-12" src="/img/logo.svg" alt="ChitChat Logo">
</div>
<div>
<div class="text-xl font-medium text-black">ChitChat</div>
<p class="text-slate-500">You have a new message!</p>
</div>
</div>
The purpose of this article is not to go into the details of how Tailwind works, but even at first glance, what we see is the difference in size of the code block, but also a series of horrible CSS classes.
Personally, I'm used to give classes a name that help me understand their meaning (button, card, grid, column, ...), and this certainly makes it easier to read the HTML code; in some way, it's like adding comments to the code. Instead, with Tailwind, the classes refer to a single specific aspect to assign to HTML tags. For each tag it's often necessary to insert more than one class, making the whole thing particularly complex.
The big advantage is that you practically don't write CSS anymore and use almost only Tailwind classes. In this way, besides not wasting time inventing class names, often even bizarre ones (item-inner-column-wrapper, etc.), you use conventions that help the site be more homogeneous and coherent.
Moreover Tailwind has a whole series of interesting features for supporting responsive sites, creating custom themes, dark mode, a plethora of plugins, and much more. For this refer to the official guide.
Tailwind and ExtJS
When some time ago I resumed an ExtJS project and found myself writing complex templates, with CSS classes and many styles, I realized I missed Tailwind. Let's take an example:
items: [{
xtype: 'list',
store: ...,
itemTpl:
'<div class="list-item">' +
'<div class="item-icon {iconCls}"></div>' +
'<div class="list-item-data">' +
'<div class="list-item-name">{name}</div>' +
'<div class="list-item-detail">{detail}</div>' +
'</div>' +
'</div>'
}]
with its CSS:
.list-item {
display: flex;
align-items: center;
padding: 4px;
}
.list-item-data {
display: flex;
flex-direction: column;
}
.list-item-name {
font-size: 18px;
}
.list-item-detail {
font-style: italic;
}
With Tailwind, the following code is enough without even touching the CSS files:
items: [{
xtype: 'list',
store: ...,
itemTpl:
'<div class="flex items-center p-1">' +
'<div class="item-icon {iconCls}"></div>' +
'<div class="flex flex-col">' +
'<div class="text-lg">{name}</div>' +
'<div class="italic">{detail}</div>' +
'</div>' +
'</div>'
}]
Configuration
Using Tailwind with ExtJS is quite simple because in the end, what the engine does is scan all our code looking for Tailwind classes (flex, grid, text-lg, p-1, p-2, etc.) and generate a CSS file containing only the classes we've used. If you use the new Open tooling based on npm, you can follow Tailwind's installation guide. Otherwise, if you use SenchaCmd, the simplest thing to do is to download the CLI from here.
With this new CLI installed, you can initialize Tailwind by going to the root directory of your project and write:
# Create a tailwind.config.js file
./tailwindcss init
This will create the tailwind.config.js
file. I changed it like this, but of course, it depends on your application:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./app/**/*.{html,js}','./index.html'],
// Remove all corePlugins
corePlugins: {
preflight: false,
},
// Remove all preset
//presets: [],
theme: {
extend: {
boxShadow: {
'outline': '2px 2px 8px 0 rgba(0, 0, 0, 0.4)',
}
},
},
plugins: [],
};
The content
option is the most important, where you must define the directories that Tailwind will scan to find CSS classes. With the corePlugins
and plugins
configuration, I removed all plugins to generate the lightest possible CSS. Finally, I added a customization to the theme to generate a new shadow-outline
class with the specified configuration. If you will, you could remove the standard presets
, but then some classes wouldn't work.
Then we can use the CLI again to generate the classes:
tailwindcss -o sass\src\tailwind.css --watch
With this command, Tailwind will constantly check the files specified in the configuration and generate the classes in the sass\src\tailwind.css
file. Finally we have to tell ExtJS to use that CSS file. We need to modify the application configuration in the scss section of the app.json
file:
"sass": {
...
"src": [
"sass/src",
"sass/src/tailwind.css"
]
]
Optionally, you can automate the creation of CSS during the production build by adding the following code to your build.xml
file:
<target name="-before-build">
<if>
<equals arg1="production" arg2="${build.environment}"/>
<then>
<x-echo message="Build CSS with Tailwind"/>
<exec executable="tailwindcss">
<arg value="-o"/>
<arg value="sass\src\tailwind.css"/>
</exec>
</then>
</if>
</target>