Style Wars: Tailwind vs. CSS-in-JS in Design Systems Implementation

Mateusz Wlekliński
Tetrisly
Published in
5 min readJun 5, 2023

When it comes to building a design system, it’s essential to compare and evaluate different technologies to ensure you’re using the best tools for your project. Not only will this help you create visually appealing applications, but it will also make it easier for designers and developers to communicate. In this article, we’ll break down the differences in technologies when building a design system and provide insights into how this can benefit your projects.

While developing our design system — Tetrisly, we encountered a problem choosing the proper styling tool for the React component library. We wanted to maximize the simplicity and flexibility of our package. So naturally, we opened a discussion regarding the choice of technology.

What @tetrisly/react should and shouldn’t be?

We talked to people outside the project and realized there was confusion about the problems the package was supposed to address. For example, many assumed we meant to create something similar to Bootstrap or Material UI.

In reality, our goal is to develop a tool for programmers working closely with UI/UX Designers to create their own design system based on Tetrisly. Tetrisly consists of tokens that are the base for building components and layouts. We aim to make it easier for a developer to create a customized design system (of course, there is no reason not to use Tetrisly without the customization).

The React implementation has to be based on a config file exported from Figma so that any change you want to make is only a matter of switching the config to apply changes to a product.

Alternatives

We narrowed it down to two libraries: Tailwind CSS and xstyled. Both prioritize a utility-first approach to building applications, which you can learn about here. They also make implementing responsive design easier and offer customizable theming options.

The packages differ in methods of implementation. For example, Tailwind is a standalone CSS library, and xstyled is CSS-in-JS. Therefore, we had to analyze each solution's strengths and weaknesses.

Below is a piece of xstyled code:

<x.div
p={{ _: 3, md: 6 }}
bg="white"
display="flex"
spaceX={4}
alignItems="center"
boxShadow
borderRadius
>
<x.div flexShrink={0}>
<img height={12} width={12} src="/xstyled.png" alt="xstyled" />
</x.div>
<x.div>
<x.h4
text={{ _: "md", lg: "xl" }}
fontWeight="medium"
color="black"
>
xstyled
</x.h4>
<x.p color="gray-500" text="sm" my={1}>
A CSS-in-JS framework built for React.
</x.p>
</x.div>
</x.div>

And the same code written using Tailwind:

<div className="p-3 md:p-6 bg-white flex space-x-4 items-center shadow rounded">
<div className="flex-shrink-0">
<img className="h-12 w-12" src="/tailwind.png" alt="tailwindcss" />
</div>
<div>
<h4 className="text-md lg:text-xl font-medium text-black">Tailwind</h4>
<p className="text-gray-500 text-sm my-1">
A Standalone CSS framework.
</p>
</div>
</div>

Criteria

The final choice of the way of building our package was based on several important points:

  • flexibility to customize based on tokens exported from Figma
  • ability to quickly translate Tetrisly tokens to styling
  • suggestions of the available tokens
  • overall developer experience
  • bundle size

Analysis

Initially, we found it challenging to decide on the technology. Then we realized that testing it out is the best way to determine which one has the potential to remain the ultimate solution. As a result, we created two minimal packages to check the pros and cons of developing using each technology.

Tailwind PoC

Tailwind provides a smaller bundle size and faster component rendering (testing on Button) as it is a relatively simple library (which may be a cause of its success). Tailwind is handy when creating static web pages and front-end applications. However, it may be less efficient when creating complex solutions. For instance, it is tough to control the styles dynamically. When attaching complicated logic to changing styles (complex components), we lose the benefits of Tailwind (suggestions, readability, simplicity) entirely.

Additionally, when trying to implement customization, we had to define tailwind config based on CSS variables for a client to be able to change our theme. Not only does it hide from us actual CSS values that are behind classes (on classname hover, you only get which CSS variable it corresponds to), but also It adds another layer of abstraction for the end user to control — If one would like to change the theme he would have to create or import config from Figma, use our CLI to create CSS variables in a separate file and import it after the previous import.

Apart from the comments above, Tailwind has the great advantage of having a big community of users, making solving problems easier. Still, given our unique needs, I don’t think many people had similar issues to what we might have in Tetrisly.

xstyled PoC

The most significant drawback of using xstyled is its speed and bundle size. In addition, it needs styled-components as its dependency, which makes it heavier than Tailwind PoC.

The simplicity of usage xstyled is similar to Tailwind — both packages embrace a utility-first approach. However, what gives xstyled its advantage is the ability to type correctly each CSS element (the user can then see the suggestions). Also, if something is too complicated to implement using xstyled inside a component, we can always use plain styled-components (as it is already a required dependency). Similarly to Tailwind, displaying actual values corresponding to tokens seems complicated — something we must consider and resolve.

xstyled allows us also to import types of specific things (like Color, Margin, etc.), then we can define the styles anywhere in the component and manipulate them if needed.

The customization is relatively easy for the end user; there can be changes in the component itself or tokens on a global scale in one application.

Conclusion

Overall, Tailwind’s faster performance and smaller bundle size make it efficient when creating standard front-end applications. However, it loses its benefits when developing complicated, dynamic styling. Also, customization by the end user seems to require a lot of hacks to work.

On the other hand, xstyled is significantly slower and bigger, but it allows us to build highly complex solutions and type them correctly for users and developers to use. Moreover, xstyled offers a great deal of customization out of the box, so minimal additional work is required.

As we considered our options and consulted with unbiased developers, we ultimately decided on xstyled over Tailwind. Our reasoning was to prioritize ease of use for developers in creating components rather than prematurely optimizing for speed. As the saying goes, "Premature optimization is the root of all evil." Listening to clients’ needs is better than making assumptions about their priorities.

Tetrisly Design System is a carefully crafted UI library with design tokens in its DNA, coming along with the free Figma plugin to manage them. Find out more here: https://tetrisly.com/

--

--

Mateusz Wlekliński
Tetrisly
Editor for

TypeScript Developer with a strong focus on type-safety clean code. Check out my portfolio: https://www.wleklinski.eu