As a junior frontend developer, I’ve experimented with various CSS approaches in my quest to find the most efficient and maintainable way to style web applications. My journey has taken me from vanilla CSS through Bootstrap and Material-UI (MUI), eventually leading me to embrace CSS-in-JS solutions, particularly Emotion with its styled components.
Over time, I’ve come to form strong opinions about different styling methodologies. One popular tool that hasn’t convinced me is Tailwind CSS. Despite its widespread adoption, I find it complicated to understand.
My Issues with Tailwind CSS
While Tailwind CSS has gained popularity, I’ve found several aspects that don’t align with my development preferences:
- Readability Concerns: Tailwind’s utility-first approach often leads to long strings of classes in HTML elements. This can make the code difficult to read and understand at a glance.
- Separation of Concerns: Tailwind mixes styling directly into HTML, which goes against the principle of separating structure from presentation. This can make it harder to maintain and update styles across a large project.
- Customization Complexity: Although Tailwind is customizable, doing so often requires additional configuration. This can be more complex than simply writing custom CSS or extending styled components. These issues led me to explore alternatives, ultimately leading me to discover and appreciate styled components.
What Are Styled Components?
Styled components are a CSS-in-JS solution that allows you to write actual CSS code to style your components. They enable you to define your styles using JavaScript template literals, keeping them scoped to specific components and reducing the risk of style conflicts.
const Button = styled.button`
background-color: blue;
border-radius: 4px;
`;
My Preferred Component Structure
One of the main reasons I love styled components is how well they integrate with my preferred project structure. For each component, I typically create a dedicated folder with the following files:
MyComponent/
├── MyComponent.tsx
└── MyComponent.styles.ts
This separation allows me to keep my component logic clean and focused while still maintaining a close connection between the component and its styles.
Benefits of This Approach
- Improved Readability: By separating styles into their own file, both the component logic and the styles become more readable. I can quickly scan the .tsx file to understand the component structure and behavior, and easily refer to the .styles.ts file for styling details.
- Modularity and Reusability: Styled components are inherently modular. I can easily reuse styles across different components or create variations of a component by extending its base styled component.
- Type Safety: When using TypeScript, styled components provide excellent type safety. I can define prop types for my styled components, ensuring that I’m using the correct props for styling.
- Easy Refactoring: If I need to change a component’s structure or styling, having separate files makes it easy to locate and modify the relevant code without affecting other parts of the application.
- Dynamic Styling: I can easily create dynamic styles based on props or theme values.
Conclusion
While Tailwind CSS offers a unique approach to styling with its utility-first methodology, my experience as a junior frontend developer has led me to prefer styled components. The clarity, modularity, and JavaScript integration of styled components align better with my workflow and mental model of component-based development.
However, it’s important to recognize that different projects and teams may have varying needs. Tailwind CSS might be an excellent fit for rapid prototyping or projects with specific design systems. As with any tool in the vast world of web development, the key is to understand the trade-offs and choose the approach that best suits your project’s requirements and your team’s preferences.
Ultimately, the goal is to create maintainable, scalable, and visually appealing web applications. Whether you choose Tailwind, styled components, or another approach, what matters most is consistency and the ability to efficiently deliver high-quality results.
Top comments (25)
Oho, this is a very interesting narrative. I want you to take a look at twin macro, use it and give feedback, I'll be waiting. If you want, you can start by looking at my guide on how to set up (here on dev.to). It has a starter pack to keep you boosted.
Use it, and tell me what you think.
Hi, very impressive! This solves two of my problems, I still have the customization complexity problem. I still feel that writing my own css with display: 'flex' etc is the same as using tailwind to just write flex. Maybe it's a habit, or just having to learn snippets in bulk, I think over time I'll realize I'm wasting a lot of time, which is why tailwind exists.
I'll give it a try though, and get back to you. I think we had the same thought process, and you were able to remedy the problem, so it should work for me too.
Alright, I'll be looking to your feedback.
Cheers, and happy coding
Your point of view is interesting, I liked it.
However, it must be taken into account that tailwind is a very good tool and not just from the point of view in terms of time optimization, an interesting point that is good to study is that it is possible to abstract tailwind classes to another class using @apply for example, tailwind is a powerful tool, but it requires a good read of the documentation to get the best out of it.
tailwindcss.com/docs/reusing-style...
Read this
Your comment highlights an important aspect that I didn't address in my article: the depth of Tailwind's capabilities. I don't deny that Tailwind remains a very powerful tool. The @apply feature you mentioned is a perfect example, with styled-components, I can do the following:
This approach allows me to create reusable styles while maintaining the component-based structure that I find intuitive. It's a great example of how different tools can achieve similar goals in ways that suit different developers' preferences and workflows.
Exactly, I particularly like Tailwind and the ways to apply it in my application, in addition to it giving you a better notion of design, I don't really like styled components, I believe that a very extensive use in a large application can affect its performance, I try to adapt the use as much as possible to use Tailwind, js-in-css I see as very problematic when the project scales a lot, but anyway I hope I have helped to have a new perspective on the use of Tailwind.
Have a good extension for fold tailwind styles marketplace.visualstudio.com/items...
e.g. press ctrl+alt+a to fold/unfold all Tailwind garbage.
Regarding any css-in-js solutions, all of them are slower than just a CSS, if you have some nested table where every cell is a styled component you will see a difference.
Main issue with plain CSS/SCSS that everybody lazy to create some set of helpers and maintain some coherent style system.
Tailwind is good for fast prototyping, and easy for AI to generate markup with tailwind. Most of software built as if they never need to support it anyway.
Tailwind is a new bootstrap basically, I assume it will follow the same path.
At the end of the day, you want UI/UX of your startup to look somehow unique, that a main downside of bootstrap/tailwind - all websites look like same template.
I 100% agree with you, while tailwind offer a very fast way to write components i feel It scale Amazing bad on the developer experience side.
Basic CSS allow you to have super junior joining your projects with Easy and styled make Ur code super readable and modular when its done right ( i use the .style notation too for separation of concern and i never been happier, i do the same stuff for typescript with .d and configuration with .conf, very Easy to search with vscode ctrlP)
On the mui part i would Say i love mui but you Need to understand if Ur project can use It, its heavy and i think It require at least One person Who know the framework well to be usefull
Thanks for the feedback. For MUI, I've felt it myself, it's slower in some aspects, but they've announced their new zero runtime css in js pigment
We've seen a 10% drop in the overall use of css-in-js over the last few years, and the cause is server side. Traditional CSS in JS works with React's context API, which only works on the client side. For me, pigment comes into play too, as you can create components that are fully renderable from build time.
I'm going to try it, and I'll probably get back to you.
I think tailwind is easy from a developer's POV but difficult to read in case of code maintainance.
I have used CSS , Bootstrap and other CSS frameworks, but when I have to develop fast from projects, I prefer TailWind.
Your view is true.
Tailwind feels like learning CSS all over again tbh.
It's great for quick prototyping, or perhaps relatively simpler things. But my go-to us CSS-in-JS stuff for larger scale things, specifically because you also get type-safety that way with TS.
+1, I immediately adapted typescript to maintain my code in the most optimal way, and allowing you to type your styled components is a real plus.
All the things in "Benefits of This Approach" could be applied to any "inline style without reusable components" vs "creating reusable components".
You're still writing css, that just like using premade / tool classes in your reusable components. Tailwind can be used with "dumb / ui components", it's not because you use Tailwind that you have to duplicate things all over the place.
The only legit criticism you could make is that Tailwind make you learn / memorize something that it's not standard compared to plain CSS. Everything else is just comparing apple to oranges.
Thank you for taking the time to provide your feedback. I appreciate your input. My preference for styled components stems from the enhanced clarity and separation they bring to my workflow. Tailwind can indeed be effectively utilized with reusable components, but I find that styled components align better with my coding style and project structure, which integrate seamlessly with TypeScript. My primary challenge with Tailwind is its non-standard approach, which requires additional learning. Each tool has its advantages, and it's a case of choosing what works best for the project and the developer.
You hit the crux of the problem on the head. If I’m going to need to make individual rules for my elements anyways, I’d rather just use SCSS and get the benefit of being able to set rules on children and siblings that don’t need class names at all.
I don’t use Tailwind for the same reason that I don’t use HTMX!
I think the same, it's an overlay to learn, but I don't think it's necessary given the level of customisation, you can quickly want to add a tailwind class to an html element but not think about all the components.
We've found Tailwind to be pretty decent at telling us when our components need to be pieced out and split apart a bit more as soon as we start re-using the same classes on multiple different elements.
Take a navigation for example - repeating the class name sequences on multiple elements means you should probably put them in a NavItem component, so that specific combination is in 1 place to maintain, and still within the context of where you're coding up the component (not a separate file to open). To each is own - at the end of the day do what makes your business the most profitable : )
Interesting article. BTW, there is this project abstracting a lot of Tailwind CSS classes.
I used daisyUI on version 2 back in the day, and they've really come on in leaps and bounds! I think I'll wait for version 5 to do a few more POCs. It's a very promising project.