by insin | 2025-10-21 00:29:47+00:00
> I’m just really interested in the problems and mental models that lead people towards Tailwind and similar tools

What a refreshing thing to read compared to the usual language in web development-related topics on HN, where people are so often talking past each other, or just here to stick the boot into the topic in general.

The first thing which comes to mind is an app I worked on which had a sidebar which only a subset of users would see, and which was the only sidebar of its type in the entire app - if you were an insurance agent, it showed you the commission you would earn on the policy you were creating for your client, and how it was calculated. So a sidebar with a couple of different types of sections, headings, an itemised list and a total, some bold text here and there, and the app's "highlight" colour in a couple of places. A true one-off, not a framework for creating sidebars.

Structurally, that meant you had the sidebar container, sections and their contents, conceptually three-deep at worst (but deeper in terms of actual element nesting). This had been added to over time, as new requirements dictated, and I was tasked with adding a new, optional section at the end, depending on the type of policy. Exactly as you said, that requires that…

> You have to identify the target element as different from other similar ones

In this case, the original developer had started out using nested SCSS (so they didn't have to name anything, either! This was in an Angluar app, where styles are scoped to components) - styling was tightly-coupled to the structure of the particular markup which was used, which was probably easy to do given whatever the original requirements were. But as this was added to over time and by other developers, this file had grown into an hilarious nest of conditions. Make this text italic only if it's nested _here_ and directly follows a heading. Use flex justify-between for items nested here and here but _not_ here. Extra wrappers to shake off the existing styling. Patch-jobs to fix up what the existing CSS did to the new elements they needed to add.

This project wasn't even using Tailwind (and still isn't) and neither was I directly at the time, but I recognised that if you looked at the rat's nest of SCSS, _all_ it was doing was setting margins, paddings, colours and font styles, and that utility classes would be a much cleaner approach which wouldn't look any less ugly than what was already there. Tailwind had already done the work of naming things, so I added a new utility stylesheet to the app and copied some of its utilities into it, and recreated the sidebar in one file in one sitting with hot-reloaded styles, using the original as reference. I ended up deleting that SCSS file. That project is now using its own utility styles for one-off stuff like that and non-reused structural styling, regular old CSS for reusable styles for things which don't merit a component of their own, and the company's design system components.

I've seen similar results in free-range CSS codebases and ones using BEM-like or other conventions too, where people have had to invent "semantic" names when they need to do something different, rather than just "look, the designer's Figma says this section needs to have a different background colour and padding". And gods forbid if they tried to DRY up that CSS by moving styles which _happened_ to be common at the time up. It's always been multiple developers over a period of time, with changing requirements, mixed skillsets when it comes to web development, who just want to get shit done and move on. You _can_ hold it right with all of these ways of doing things, but if people are underthinking or undercaring about it, it doesn't tend to happen. Tailwind doesn't have a fix for that either, it just localises the blast radius somewhat.

This is my mental model for why I'm using Tailwind today in a React app, or any other component-based app framework or library: when I get requirements for a new chunk of UI I need to build, I'm immediately thinking about the state and the behaviour, I'm looking at what the designer has done in Figma, I'm mentally breaking down the layout into flexboxes and grids and spacing and our design system components in my mind, and I'm mentally mapping out the CSS for those. I create a new file, I sketch out the state and behaviour, I start creating the structure. I have the file open in my editor, the new component is hot-reloading in the browser. Tailwind is now the most route one way for me to translate what's in my head to the screen and get instant feedback. In the time it would have taken me to think of a name for a new CSS rule, add even just `display: flex;` to it and add the class name to the element, I've already typed `p-2 flex items-center gap-2` and started tweaking those spacings to match the design. Flip the app to dark mode. Tweak tweak tweak with some `dark:` classes and the design tokens we've added to our Tailwind config, all auto-completed nicely in the editor. Dark mode is done. Oh, what should this do on smaller screens? Reduce the size of the window. Tweak tweak tweak with some `md:`, `xs:`, whatever classes. Resize. Tweak. Resize. Tweak... Responsiveness is done. Now it needs to respond based on behaviour, let's `hover:` here and `focus:` this and `focus-within:` that and conditionally apply these properties here based on state. All in one file and one browser window for feedback. Nothing that can't be done perfectly fine in a regular stylesheet, but just so much less friction while implementing, in the same way that I'm also no longer thinking of identifiers to attach event handlers to and sticking code for those in a separate file.