Hello! Have you tried or want to try Tailwind CSS? Perfect, I'll be sharing some important things about Tailwind CSS.
It's not exactly the 'best practices' either. It's more about coding style and some tips that make me comfortable using Tailwind CSS.
It's opinionated, but who knows, i hope something positive can be taken from it.
Coding Style
Here is the coding style for writing Tailwind CSS classes that I often use, divided into 3 important points: sorting, splitting and grouping.
Sorting
Try to take a look at the following Button component example, so many classess 😂
<button
class="inline-flex h-10 items-center justify-center gap-1.5 rounded-md border border-transparent bg-purple-600 px-4 text-center text-sm font-bold text-white transition duration-150 hover:bg-purple-700 dark:bg-purple-600 dark:hover:bg-purple-500 md:rounded-xl"
>
Button Text
</button>
Because dealing with a large number of classes for just single element, class sorting is quite important.
Fortunately, Tailwind CSS itself has provided the Prettier plugin to handle this matter.
Consistent class order will make the maintenance process easier in the future.
For example, in the sample, with the classes already sorted, we can easily change the border
and border-transparent
because they are next to each other.
Or easily change the hover:
styles or breakpoints because they usually appear at the end of the class.
Splitting
To make it neater, we can split the class into several strings or lines. I usually use clsx for this.
An example of a Button
component that has already used clsx
:
function Button({ children }) {
return (
<button
className={clsx(
'inline-flex h-10 items-center justify-center gap-1.5 rounded-md border border-transparent bg-purple-600 px-4 text-center text-sm font-bold text-white transition duration-150 hover:bg-purple-700 md:rounded-xl',
'dark:bg-purple-600 dark:hover:bg-purple-500'
)}
>
{children}
</button>
);
}
Grouping
After the classes have been splitted, we can 'group' them to make it neater and more readable.
The pattern I usually apply is:
group 1
: default utilitiesgroup 2
: breakpoint utilitiesgroup 3
: dark mode utilitiesgroup 4
: other variants utilities
Let's implement this into previous Button
component:
function Button({ children }) {
return (
<button
className={clsx(
// group 1
'inline-flex h-10 items-center justify-center gap-1.5 rounded-md border border-transparent bg-purple-600 px-4 text-center text-sm font-bold text-white transition duration-150',
// group 2
'md:rounded-xl',
// group 3
'dark:bg-purple-600 dark:hover:bg-purple-500',
// group 4
'hover:bg-purple-700'
)}
>
{children}
</button>
);
}
Or with the CSS component:
.button {
/* group 1 */
@apply inline-flex h-10 items-center justify-center gap-1.5 rounded-md border border-transparent bg-purple-600 px-4 text-center text-sm font-bold text-white transition duration-150;
/* group 2 */
@apply md:rounded-xl;
/* group 3 */
@apply dark:bg-purple-600 dark:hover:bg-purple-500;
/* group 4 */
@apply hover:bg-purple-700;
}
Much better, I think. Groups 2, 3, and 4 can still be improved or adjusted to your preferences, just make sure to maintain consistency in writing.
Tips
Use Component
If you feel that some elements have same styles, they can be split into separate components, such as buttons.
Since I'm using React, I can create the component like:
function Button({ children }) {
return (
<button
className={clsx(
'inline-flex h-10 items-center justify-center gap-1.5 rounded-md border border-transparent bg-purple-600 px-4 text-center text-sm font-bold text-white transition duration-150',
'md:rounded-xl',
'dark:bg-purple-600 dark:hover:bg-purple-500',
'hover:bg-purple-700'
)}
>
{children}
</button>
);
}
Use Class Component
In a static site, classes are served as is. Therefore, if we have elements that use the same set of utilities multiple times, it will increase the size of our HTML file.
For example, see this repeated utilities on these pagination buttons:
<button
class="inline-flex h-10 items-center justify-center gap-1.5 rounded-md border border-transparent bg-purple-600 px-4 text-center text-sm font-bold text-white transition duration-150 hover:bg-purple-700 dark:bg-purple-600 dark:hover:bg-purple-500 md:rounded-xl"
>
Previous
</button>
<button
class="inline-flex h-10 items-center justify-center gap-1.5 rounded-md border border-transparent bg-purple-600 px-4 text-center text-sm font-bold text-white transition duration-150 hover:bg-purple-700 dark:bg-purple-600 dark:hover:bg-purple-500 md:rounded-xl"
>
1
</button>
<button
class="inline-flex h-10 items-center justify-center gap-1.5 rounded-md border border-transparent bg-purple-600 px-4 text-center text-sm font-bold text-white transition duration-150 hover:bg-purple-700 dark:bg-purple-600 dark:hover:bg-purple-500 md:rounded-xl"
>
2
</button>
<button
class="inline-flex h-10 items-center justify-center gap-1.5 rounded-md border border-transparent bg-purple-600 px-4 text-center text-sm font-bold text-white transition duration-150 hover:bg-purple-700 dark:bg-purple-600 dark:hover:bg-purple-500 md:rounded-xl"
>
3
</button>
<button
class="inline-flex h-10 items-center justify-center gap-1.5 rounded-md border border-transparent bg-purple-600 px-4 text-center text-sm font-bold text-white transition duration-150 hover:bg-purple-700 dark:bg-purple-600 dark:hover:bg-purple-500 md:rounded-xl"
>
4
</button>
<button
class="inline-flex h-10 items-center justify-center gap-1.5 rounded-md border border-transparent bg-purple-600 px-4 text-center text-sm font-bold text-white transition duration-150 hover:bg-purple-700 dark:bg-purple-600 dark:hover:bg-purple-500 md:rounded-xl"
>
Next
</button>
Imagine if in one HTML file there are several paginations as well, the size of the HTML file will definitely be bigger!
To reduce it, we can abstract or create CSS components instead. So, we can transform the element utilities to CSS component, like:
<button class="pagination-button">Previous</button>
<button class="pagination-button">1</button>
<button class="pagination-button">2</button>
<button class="pagination-button">3</button>
<button class="pagination-button">4</button>
<button class="pagination-button">Next</button>
!important Usage
Like vanilla CSS, try to avoid using !important
.
In Tailwind CSS, !important
can be added by adding the !
prefix to the utility class, for example, !p-2 !px-3
.
Try to avoid it as much as possible! Once trapped into using it, all your utilities may end up with many !important
and it will be very difficult to make style changes in the future.
Conditional Class
<div className={`text-black ${dark && 'text-white'}`}>
Hello, World!
</div>
<div className={dark ? 'text-white' : 'text-black'}>
Hello, World!
</div>
Let me explain a bit.
If we use the first method and the value of dark
is set to true, then the class would be text-black text-white
.
In some cases, the result might be as expected. However, in some cases, it might cause a problem.
It's possible that the text remains black even when the value of dark
is true.
Let the code speak:
<!-- Some elements within the project. -->
<div class="text-white">White!</div>
<div class="text-black">Black!</div>
<!--
The above elements will generate CSS in the following order:
.text-white {
...
}
.text-black {
...
}
-->
<!--
Imagine that "dark" is set to true, and use a class defined as follows for conditional class:
class={`text-black ${dark && 'text-white'}`}
-->
<div class="text-black text-white">Still black? CSS Specificity!</div>
<!--
That's because, in this example, both "text-black" and "text-white" have the same CSS properties and specificity.
On the other hand, the last one defined in the CSS file (in the previously generated CSS) will take precedence!
-->