Why We're Migrating to Tailwind

A wheat field moving in the wind

Let’s face it: styling is not always a piece of cake. As applications grow larger in size, so does the complexity of adding, modifying and organizing CSS styles. Or so it used to be?

Our engineers were looking for ways to improve the process of styling our application - and after discussions within the team - placed their bet on Tailwind.

Why Tailwind?

Adding and maintaining CSS styles can pose different challenges. Naming is one of them, despite common patterns like the BEM naming convention. While these patterns often provide helpful solutions, we faced weaknesses when applied in a context where multiple engineers have different interpretations of how these patterns should be applied. Style guides and extensive documentation help on that matter at the cost of a certain communication overhead.

Furthermore, refactoring CSS has challenges on its own as it is sometimes not trivial to find dead and repeated code. What’s more is that breaking changes are potentially harder to notice as the visual changes may only be visible under certain conditions or in one of a multitude of different pages.

We are still in the process of moving our interfaces and components to Tailwind but nonetheless, we are excited to share some ways Tailwind is helping us style our platform.

Hand peeking through leaves, giving a thumbs up

Bringing design & engineering together

Tailwind is configured by utilizing a configuration file. We were delighted to see that while it ships with sensible defaults, everything from colors and spacings to font sizes and borders can be added, modified and extended.

module.exports = {
  theme: {
    colors: {
      transparent: 'transparent',
      current: 'currentColor',
    
      'refurbed-blue': {
        100: '#c8cde1',
        200: '#a5adcd',
        300: '#6a74a9',
        // ....
        900: '#171933',
        default: '#2f3061',
      },
      extend: {
        boxShadow: {
          rb: '0 16px 20px -5px rgba(78, 127, 227, .5), 0 8px 8px -5px rgba(78, 127, 227, .8)'
        },
        fontFamily: {
          sans: [
            'Source Sans Pro',
            ...defaultTheme.fontFamily.sans,
          ]
        },
      },
    },
  },
}

This helps us to bring our design team closer to our engineering structure as we can port our design system, defined in Figma, to Tailwind easier than with other frameworks we have tried in the past. We have therefore established a certain “rule set” and by adhering to this set of utilities, our developers can bring designs to life quicker than before.

This setup has also aided us while refactoring our CSS code. Instead of changing CSS styles in stylesheets, everything is consolidated in a single file - changes in this file are then neatly applied throughout the whole platform.

Focus on styling, not on naming

As mentioned previously, large projects tend to make it increasingly hard to provide meaningful naming to their styles. As a result, many different patterns and strategies have emerged - BEM naming convention, CSS-in-JS and CSS modules to name a few.

Tailwind bypasses this problem by providing fixed naming schemes for the utility classes it generates based on the config file. This enables us to focus more on the styling instead of debating whether it should be a BEM –identifier or _block element. A nice side benefit is that engineers do not need to spend time to determine where new styles should be put as everything is applied directly using Tailwind’s classes.

Let’s look at an example where we create a hypothetical person card which displays an avatar, the name and a short paragraph. The first card is implemented using BEM naming conventions while the second one uses Tailwind’s utility classes.

See the Pen Tailwind vs Normal Avatar by Patrick Ahmetovic (@patriscus) on CodePen.

In the example above, we are able to infer the styling by looking at the HTML markup itself. On top of that, we have reduced potential discussion points by utilizing standard utility class names. Truthfully, Tailwind markup may look daunting at first but becomes very intuitive after a short amount of time.

Small file size using PurgeCSS

Through the usage of PurgeCSS, Tailwind is able to strip out any styles that are not actively used in files you specify. Gone are the days of carefully selecting the modules you need - potentially breaking the pages because the thing that we for sure don’t need turned out to be something that we actually use. The following example demonstrates how trivial it was to enable purging for our engineering blog:

module.exports = {
  purge: {
    content: ['./layouts/**/*.html', './content/**/*.md'],
  },
}

The benefits can be immediately seen. Providing automated methods to spare users to unnecessarily download large chunks of data is one of the biggest advantages we have come to love about using Tailwind.

A wood with green trees, one tree in the center having yellow leaves

However, despite the advantages we have noticed certain aspects that provide different challenges.

One-off styling

While we previously said that having a configuration file is helping us in achieving a common rule set between the design team and engineering, it is also the source of an issue we have faced: one-off styling.

In a perfect world the designs are always composed of well-defined utilities. However, this is not always feasible. One-off styling therefore poses the problem of deciding how to handle it: add it to the configuration? use inline styling instead? add CSS rules to a stylesheet?

This is an ongoing discussion as we have yet to see how each of the solutions scale in the future. While we were successful with both inline styles and external stylesheets, it is to be determined what the standard way for our engineering process will be.

Markup may get polluted

One of the core premises of Tailwind is to apply utility classes to your HTML markup. This has the benefit of being able to infer how the element will look at the cost of adding additional markup to the HTML.

While being something we have considered, our general experience as of now is that this issue is not as relevant as one might expect. The benefit of using common utilities combined with not having to jump from stylesheet to stylesheet outweighs the additional classes you might add to your class attribute.

Roundup

Going forward, we encourage our frontend developers to use Tailwind for all our new components and elements. In addition, we agreed on slowly but continously migrating old styles as well to form a cohesive code base.

Tailwind has proven itself to be a framework that enables us to write easier to maintain code, while being customizable enough so that we are confident it will also adapt to our future needs.

Written by

Patrick Ahmetovic

December 22, 2020

Patrick is a frontend developer based in Austria, focusing on the public-facing features of the refurbed platform.

We're Hiring

  • Lead Frontend Developer / Vue.js (m/f/x)

    We are looking for a lead frontend developer with experience in Vue.js to support us in developing our interfaces and to lead a remote team of software developers.

  • Lead Backend Developer / Go (m/f/x)

    We are looking for a lead backend developer with a solid background in designing and implementing Go backend services to support us in improving our e-commerce platform and to lead a remote team of software developers.

  • Senior Data Engineer (m/f/x)

    We are looking for a senior data engineer to work in the intersection between engineering and data science. Help us improve our data processing workflows and push them to the next level.

View all positions