· engineering · 7 min read
Tailwind CSS: The good, the bad and the ugly.
A critical look at Tailwind, the pros, cons and alternatives.
Table of Contents
Tailwind is undeniably popular, offering an easy, quick, and convenient way to style HTML without needing to write any CSS. But convenience often comes with a hidden cost- plastic bags, disposable coffee cups, inline styles - our world is littered with comfortable, convenient time savers - many of which we later come to regret - will Tailwind be one of them?
A bit about Tailwind.
In case you’ve not come across Tailwind yet, it offers a (mostly consistently named) set of utility classes one can apply to DOM elements to have them styled - for example text-center
or bg-white
. If you’re familiar with Bootstrap, you’ll be familiar with utility classes. Almost all CSS rules, including light/dark modes and media queries, can be represented with Tailwind.
Unlike bootstrap, Tailwind classes can be combined with variants (for example :hover
) and extended with plugins. As a result the number of potential classes approaches infinity. Tailwind uses PostCss and PurgeCss to achieve this and ensure that only those styles you’re actively using are in its output.
Like any good CSS framework, Tailwind comes with sane defaults, giving a rather clean, modern look (though the same was said of Bootstrap at the time), Of course it’s easy to apply themes to customize and overwrite these defaults to suit your needs.
Due to its ease of use, low barrier to entry and great features, documentation, and community, Tailwind is extremely popular, and is a popular default tool choice for many developers, similar to Bootstrap in its prime. However, before jumping in it’s worth pausing to take a critical look at it. Though this is true of most things, it’s particularly worthwhile with Tailwind, as we will see.
What’s the downside?
While it’s true tailWind is a joy to use, and it makes it quick and easy to get a clean and consistent looking UI, it’s not without its drawbacks.
Tailwind seems to encourage (by accident or design) a mindset of avoiding CSS, which I disagree with. CSS is a huge part of the frontend, we shouldn’t be sidestepping it, or avoiding it. It has it’s quirks, and there’s a lot to learn, but it is the basis of all web styling and it has one massive advantage over Tailwind, it cascades. The cascading nature of CSS allows child elements to inherit styling rules from their parents rather than having to style each individual item, keeping styles concise, reusable and maintainable.
Below are the major drawbacks to using Tailwind that I see.
- It’s verbose I don’t think it’s possible to exaggerate just how verbose Tailwind styling can become. The following is a class plucked from one of the templates of this site. As Tailwind goes it’s not unusually long, there are much bigger examples out there, yet it’s still hard to grok.
- It doesn’t cascade As mentioned above, Tailwind classes only apply to the item they are added to, which makes controlling child elements (for example in markdown) tricky. To solve just that problem, there is a typography plugin which allows the styling of elements within prose elements from the parent. The mere existence of this somewhat hacky workaround really highlights the problem in my opinion.
- Conditions are complicated Where previously one may have added the class
active
to an active item, to apply the appropriate styles, with typescript we need to conditionally add/remove or edit the classes on each the elements themselves. It’s results in ugly, hard to read code that’s difficult to reason about and easy to introduce errors to. - You still need to know CSS While it does have a low barrier to entry at first - the majority of Tailwind classes are named similarly to their CSS equivalents, and after using it for a while you essentially just learn CSS terminology and concepts - without any of the portability or benefits this entails.
- Specificity To determine which styles to apply to an element, CSS uses it’s concept of specificity. Styles applied to classes are more specific than those of elements, making Tailwind styles quite hard to overwrite, especially if using Tailwinds
!important
modifier. - You need to be a dev Some companies are lucky enough to have great web designers/developers who might not be top of front end JS frameworks, but really know their styling stuff - it’s not really possible to hand html with Tailwind over to designers for a bit of a tweak - the changes have to come from developers, and they have to come from developers with the ability to maintain the functionality. It makes separating concerns and skills somewhat harder.
- Hardcoded design Unless we’re passing classes as props everywhere, we end up hardcoding the design and appearance of our components alongside their functionality. Which some people might like, but to be me feels wrong, and a violation of separation of concerns.
- Maintenance burden Refactoring a large project, with numerous components, would be a nightmare. Having to read, understand and adjust the endlessly verbose lists of classnames applied to all elements, and write/update tests to match would be an endless repetitive grind, error prone and likely to be put off for as long as possible. Similarly, trying to get consistent styling across all like elements in a large team, especially when new heads join is a challenge.
What is it good for?
Despite the drawbacks listed above, Tailwind can still be an excellent choice in many situations. Its approach allows developers to build user interfaces quickly without writing custom CSS, which makes it particularly suitable for proof-of-concept projects, internal tools, or any short-term projects where the emphasis is on functionality over long-term maintainability. For startups and small teams working on tight deadlines, Tailwind can streamline the development process, ensuring a consistent and clean UI with minimal effort.
Tailwind is also well suited in situations where there are less resources for, or less attention to, design, or in developer-centric teams where developers are responsible for both functionality and styling. Tailwind’s predefined classes and responsive design allow for the creation of adaptive layouts without diving deep into custom CSS, making it easier to achieve a polished look even with limited design resources.
Alternatives
While Tailwind is a compelling choice for styling, especially during rapid development, it’s worth considering some of the alternatives:
- Vanilla CSS It’s been around for, and is better than, ever. CSS provides all you need to style your elements. Using a preprocessor like Sass or Less provides features like variables, mixins, and nesting, making complex stylesheets more manageable and helping you to write clean, maintainable CSS. However the challenges of maintaining stylesheets for large applications are well documented and in part, are what have led to the search for alternatives.
- CSS Modules An attractive middle ground that allows you to access all the power and inheritance that CSS offers, whilst being able to restrict the scope of the CSS and see in the IDE where/how it is being used. CSS Modules are definitely worth considering.
- CSS-in-JS Popular before Tailwind, packages like Styled Components or Emotion allow you to write css directly within your javascript components, offering similarly rapid development, but at the cost of having design and functionality tightly coupled, leading to similar potential maintenance issues later on.
- Other frameworks There are of course alternative frameworks, offering either utility css classes, styled components or some of each. Bulma is a popular one, Bootstrap is (apparently) still going strong, and component libraries like materialUi and mantine for react are popular too.
Conclusion
Tailwind CSS offers a valuable solution for rapid UI development, making it easy to start and ensuring a consistent look. However, its verbose class names and maintenance challenges can be significant drawbacks, especially in large projects. Alternative styling methods, might provide more flexibility and control. Ultimately, the best choice depends on the project’s needs and the team’s preferences. Understanding the strengths and weaknesses of each approach helps developers make informed decisions and select the right tool for the job.
About James Babington
A cloud architect and engineer with a wealth of experience across AWS, web development, and security, James enjoys writing about the technical challenges and solutions he's encountered, but most of all he loves it when a plan comes together and it all just works.
No comments yet. Be the first to comment!