tldr;
I recently led a workshop on Angular and Tailwind for ng-conf 2021. The purpose was to introduce Angular developers to Tailwind, including how to implement it in your app and how to use Tailwind. A couple weeks after the event an attendee reached out with a couple questions and I decided to write an article about it. Hopefully this will be helpful to others that are using Tailwind in enterprise apps, or really any size apps.
The questions were:
- What are the big differences between Bootstrap and Tailwind
- My thoughts on the amount of CSS in templates with Tailwind, and alternate solutions
I'll tackle each of those to the best of my ability in this article.
Bootstrap vs. Tailwind
Okay, excuse the heading for this section. I hate "Technology X vs. Technology Y" articles. They're the worst. So I'm not really going to do that in this article. Bootstrap is a great CSS framework and there's a reason it's been as popular as it has been for nearly a decade. It provides an easy way for those who don't have much design skill to end with a decent looking application. However, there are some minor downsides to Bootstrap. One thing is that Bootstrap sites tend to have a familiar look and feel. You can usually go to a site and tell that it's been built using Bootstrap. Another downside is that Bootstrap has specific classes for particular components that you have to remember for each of those components. For example, if you want to put a card on the page, here's the HTML and classes:
<div class="card" style="width: 18rem;">
<img src="..." class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
As you can see, there is a .card
class on the enclosing div
, as well as .card-body
, .card-title
, and .card-text
classes. What do these classes do exactly? I don't know, except that they add some style to those particular elements. The style on those elements can't really be reused elsewhere; for example if you want to use an .accordion
. The .accordion
classes are different than the .card
classes, even if they result in similar output. Now, what does this mean for you as a developer? It means that memorizing the classes for your application is more difficult because there are different classes for every component, as well as all the utility classes that Bootstrap provides.
The final difficult part about Bootstrap, historically, has been that overwriting the default Bootstrap styles is nearly impossible. There are many !important
s littered throughout the Bootstrap style files. In addition, the specificity on certain elements is deep. For example, it's not uncommon to see a CSS rule like this:
.card > .card-body > p.card-text {
font-size: 16px !important;
}
So not only is there a !important
, the rule is very specific. In the end, it's hard to overwrite Bootstrap styles.
Now, Tailwind has similarities to Bootstrap in that it makes it easy for the average developer to produce a good looking application. It also uses utility classes like Bootstrap does, but it only uses utility classes. You won't find card specific classes anywhere because the folks at Tailwind don't know how you want your card to look. Each card you make can look different if you want. If you want three variants, make three variants. It's completely up to you. This flexibility is refreshing. Nobody will come to your site and say, "This is a Tailwind site." They will have no idea. The sky is the limit for how to design your site.
What's With All the Classes?
The second question is another that I have received a few times, and that is, "How do you deal with all the classes littered throughout your HTML?" And honestly, it's a good question. If you've never seen a sample of some HTML with CSS classes, here's one for you:
<footer class="bg-white" aria-labelledby="footerHeading">
<h2 id="footerHeading" class="sr-only">Footer</h2>
<div class="max-w-7xl mx-auto py-12 px-4 sm:px-6 lg:py-16 lg:px-8">
<div class="xl:grid xl:grid-cols-3 xl:gap-8">
<div class="space-y-8 xl:col-span-1">...</div>
<div class="mt-12 grid grid-cols-2 gap-8 xl:mt-0 xl:col-span-2">...</div>
</div>
<div class="mt-12 border-t border-gray-200 pt-8">
<p class="text-base text-gray-400 xl:text-center">
...
</p>
</div>
</div>
</footer>
There are a lot of classes mixed in there! And this is just a small example, a little over 10 lines of HTML. So, how do I deal with that? It's simple: I just do. It took a little while, but I finally realized that having all the classes looks a little crazy when developing a page or component, but it really doesn't matter. I can use all the utility classes provided by Tailwind, or write custom CSS. I can have long strings of classes, or long files of SCSS for each component or my app. I've decided that overall, it's much easier to add a whole bunch of classes to my HTML rather than write the custom CSS.
Now, there is somewhat of a middle ground. It does seem kind of crazy to apply a color and underline to every single a
tag in the app. Or, more complicated, apply the same classes over and over again to every button. How can we solve this problem? Let's look at 3 ways:
@apply
The first is the apply
directive that you can use in SCSS files. This directive lets you apply (hence the name) certain Tailwind classes to a CSS selector. Here's an example:
a {
@apply text-blue-500 text-underline;
}
This rule will target all a
tags and apply a color and underline to them. That way you don't need to add those classes in the HTML files.
theme()
The next method is using the theme
function in SCSS files. Its purpose is similar to @apply
, but is used with specific CSS rules. You can view the specifics at the link, but here's an example of how to use it:
.btn-blue {
background-color: theme('colors.blue.500');
}
In this case, a custom CSS class is created, called .btn-blue
, and the background of the button is set to the blue 500 variant.
Angular Directives
The last option available specifically to Angular developers is to create and use an attribute directive. Attribute directives provide the ability to change the appearance or behavior of DOM elements and Angular components. With the attribute directive, you could apply all the required classes for a button, and provide the color of the button as the input to the directive. That way you ensure that all the buttons in your application are the same each time a button is used. Here's an example of an attribute directive for a button:
@Directive({
selector: '[myButton]',
})
export class ButtonDirective implements OnInit, OnChanges {
private defaultClasses: string = DEFAULT_BUTTON_STYLES;
@Input('myButton') buttonColor: string;
@HostBinding('class')
elementClass: string = `${this.defaultClasses}`;
ngOnInit() {
this.setColor();
}
ngOnChanges(change: SimpleChanges) {
if (change?.myButton?.currentValue !== change?.myButton?.previousValue) {
this.setColor();
}
}
setColor() {
if (this.buttonColor) {
this.elementClass = `${this.defaultClasses} ${BUTTON_COLOR_STYLES[this.buttonColor] || ''}`;
} else {
this.elementClass = `${this.defaultClasses}`;
}
}
}
To use the directive:
<button myButton="orange">Hey there!</button>
This would make the directive apply the default button styles, and then the orange classes that you've selected as well.
Conclusion
Tailwind is a great option for developing Angular applications. There are some things that you may have to overcome (like all the classes) but for me the benefits outweigh the downsides. The flexibility that Tailwind provides makes building applications really nice. For me, Tailwind is the way to go. It will surely not be the last CSS framework I use, but it is my current choice.
Top comments (0)