Migrating to Tailwind CSS

Tailwind is a popular CSS framework which is highly customizable and optimized for speed. This is how Asserts migrated to Tailwind.

Migrating to Tailwind CSS

Asserts project was initially built with MUI and it served us well, until we encountered a challenge during the update from version 4 to version 5. The migration required a shift in the approach of writing styles, with the previous use of JSS being replaced by emotion. Unfortunately, this change made the migration significantly more difficult, making it feel almost impossible to achieve. In order to facilitate the migration process, we realized that we needed to install additional packages such as @emotion/styled, while continuing to use the @mui/styles library (which is considered legacy by the MUI team in v5). However, upon further consideration, we came to the conclusion that this approach did not align with our needs and we began exploring alternative solutions. It became evident that the migration would not be a straightforward process and would require significant effort to overcome the challenges presented.

Tailwind CSS

Upon reading the book Refactoring UI, written by the Tailwind team, we were thoroughly convinced of the framework's efficacy and subsequently chose it as the primary library for writing custom styles in our project, in addition to utilizing the core MUI components.

Tailwind CSS is a popular utility-first CSS framework that allows developers to rapidly build user interfaces with pre-defined classes. It is highly customizable, responsive, and optimized for speed. If you are looking to migrate an existing project to Tailwind CSS, here are some key steps you can follow.

Why Tailwind CSS?

There are several reasons why you should consider using Tailwind CSS in your web development projects:

  1. Efficiency: With Tailwind CSS, you don't need to write custom CSS styles from scratch, as the framework provides pre-built classes that can be easily applied to HTML elements. This saves time and effort and allows you to focus on building functionality rather than thinking about class names.
  2. Customizability: Tailwind CSS is highly customizable, with a configuration file that allows you to modify and extend the default settings to suit your specific needs. You can add or remove classes, change colors, adjust spacing, and more.
  3. Responsive Design: Tailwind CSS offers extensive support for responsive design, with built-in breakpoints that allow you to adjust the layout of your website based on screen size. This makes it easy to create mobile-friendly designs without having to write complex media queries.
  4. Consistency: By using pre-built classes, Tailwind CSS ensures consistency across your website, making it easier to maintain and update in the future. This is especially useful for large-scale projects where consistency is crucial.
  5. Efficiency: By using atomic classes, Tailwind CSS reduces the amount of CSS code required, resulting in faster page load times and improved website performance.
  6. Accessibility: Tailwind CSS provides an accessible option for developers of all skill levels, with an easy-to-learn syntax and a supportive community that offers resources and guidance.

Tailwind CSS: Disadvantages

  1. Styling and HTML are Mixed. One of the potential downsides of using Tailwind CSS is that styling and HTML can be mixed, which may make it challenging to maintain and update the codebase. In traditional CSS, developers write a separate stylesheet that contains all the style rules, and then reference those rules in the HTML using classes or IDs.
    Additionally, it can be challenging to ensure consistency in styling across multiple pages, as styles are directly applied to HTML elements rather than being centralized in a separate stylesheet.
    To mitigate these issues, developers can use best practices such as organizing styles into reusable components and using consistent naming conventions for utility classes.
  2. Learning Curve. Tailwind CSS has a unique syntax and utility-first approach, which may require some time to learn and understand, especially for developers who are used to traditional CSS. However, once you become familiar with the framework, it can save a significant amount of development time. Utilizing Tailwind CSS IntelliSense can be a valuable aid for developers who are learning and becoming proficient with the framework.
  3. Lack of basic components. Tailwind CSS is not a traditional components library. Unlike libraries such as MUI or Bootstrap that provide pre-designed components, Tailwind CSS is a utility-first CSS framework that focuses on providing a set of low-level utility classes that can be combined to create custom designs.
    There is a library that partially solves this issue. HeadlessUI is an open-source library that provides a set of customizable and accessible UI components that do not include any styling or layout out-of-the-box. The library is designed to be used in conjunction with other UI frameworks, such as Tailwind CSS or Bootstrap, to provide a flexible and customizable UI-building experience.

Migration plan

Once we have a good understanding of Tailwind CSS, we can start planning the migration. This involves identifying the parts of the project that need to be updated, such as CSS files, MUI theme, and components.

MUI and Tailwind

The MUI framework has created a guide to using Tailwind CSS with MUI. This guide provides detailed instructions on how to integrate the two frameworks seamlessly, allowing developers to take advantage of the powerful features of both. To align our MUI framework with Tailwind CSS, we began by adapting our MUI theme to fit the Tailwind theme. As a first step, we opted to utilize the Tailwind color palette, which required us to update all color references in the application code to correspond with Tailwind classes. As an illustration, here is an example of how this was achieved within our MUI theme.

import tailwindColors from 'tailwindcss/colors';


const getTheme = (mode: AppThemeType) => createTheme({
    palette: {
      mode,
      ...(mode === 'light'
        ? {
            background: {
              default: tailwindColors.neutral[50],
            },
            divider: tailwindColors.gray[200],
          }
        : {
            background: {
              paper: tailwindColors.neutral[800],
              default: tailwindColors.neutral[900],
            },
            divider: tailwindColors.neutral[600],
          }),
    },
});

Removing @mui/styles dependency

It was time to remove the redundant and legacy dependency on @mui/styles. However, before doing so, we had to convert the styling of around 300 files to JSX Tailwind classNames. Although it was a challenging task, it was worth the effort. By completing this process, we were able to fully leverage the power of Tailwind across the entire application, resulting in greater control and flexibility over our styling choices.

Example of file migration from @mui/styles to Tailwind CSS

Tailwind tips

In this section, we will discuss some general recommendations for developing with Tailwind CSS. These tips will provide valuable insights to help you optimize your workflow and make the most of the features provided by this powerful framework.

Tailwind CSS Cheat Sheet

For those who are already familiar with CSS, learning the Tailwind syntax can be intimidating. It can be challenging to identify the appropriate Tailwind class when transitioning from familiar CSS concepts. However, Tailwind CSS Cheat Sheet is an excellent resource to make this process easier. They provide a quick and easy reference for identifying the appropriate class, making it much simpler to master the Tailwind syntax.

Tailwind CSS Cheat Sheet

Keep it simple

This concept is well described in the Tailwind docs here:

Tailwind encourages a utility-first workflow, where designs are implemented using only low-level utility classes. This is a powerful way to avoid premature abstraction and the pain points that come with it. You will be surprised at how often this ends up being the best solution. If you can quickly edit all of the duplicated class lists simultaneously, there is no benefit to introducing any additional abstraction.

Totally agree, and I believe people often stay away from this approach because they fear repetition. However, in many cases, it's the simplest and most maintainable solution, so there's no need to avoid it.

Avoid using @apply

@apply is a feature in Tailwind CSS that allows you to define your own custom classes by composing multiple utility classes. It enables you to create a reusable set of styles that can be applied to different elements throughout your project.

However, there are some potential downsides to using @apply. One issue is that it can create a "magic abstraction" where it's unclear exactly which utility classes are being used to create the custom class. This can make it more difficult to debug and maintain your codebase over time. Additionally, @apply can result in larger CSS files, which can slow down page load times and make it harder to optimize your site's performance.

While @apply can be a useful tool in some cases, it's generally recommended that you use it sparingly and with caution. Instead, Tailwind provides a wide range of pre-defined utility classes that can be combined to create the most common styles, and you can also create custom utility classes using Tailwind's built-in functionality without using @apply.

A tweet about @apply from the creator of Tailwind

Automatic Class Sorting with Prettier

Prettier plugin for Tailwind CSS can help improve your code consistency and organization. When you use Tailwind, it's easy to end up with a large number of utility classes applied to a single element, which can make the HTML code hard to read and maintain. Automatic class sorting can help alleviate this issue by grouping similar classes together and separating them with whitespace, making it easier to scan and understand the code.

Prettier is a code formatting tool that can automatically sort Tailwind classes in a consistent and logical order. By enabling the sortAttributes option in Prettier, you can ensure that your classes are always sorted in the same way across your entire codebase, even if different developers are working on different parts of the project.

Overall, using automatic class sorting with Prettier can help improve the readability and maintainability of your code, making it easier to work with and modify over time.

Conclusion

Libraries like MUI, Bootstrap, Chakra, etc, among others, are designed to solve a particular problem: the desire to avoid styling an application. However, as front-end developers, it's essential to take ownership of our style systems and solutions, enabling us to create applications that aren't restricted by the libraries we choose.

We particularly favor Tailwind because it enhances our ability to develop style systems quickly, improves CSS skills, and enables us to create exceptional applications without a ceiling on quality. Unlike other solutions, it doesn't limit what we can ship, providing greater flexibility and customization options.

Tailwind is transforming how we architect our applications, and we encourage you to give it a try. In our case, we have a significant codebase with MUI and can't eliminate it entirely. However, by combining MUI with Tailwind, we are not limited by the library and can create applications that meet our highest standards.