To have 'mix phx.new --no-tailwind' to just do not use Tailwind, but still create basic CSS

I was trying to exercise some restraint in not getting into this but since it seems the discussion has drifted in this direction anyway, I’d like to argue in defense of OP and against Tailwind as a default.

I think Tailwind was a mistake - both for the “industry” and for Phoenix. Like many I actually quite liked using Tailwind in the past, but it is fundamentally a degenerate solution. Throwing away standards in favor of a bespoke class generator tool solves some of the problems with CSS, but at the cost of, well, throwing away standards. If you use Tailwind you are always one step behind real CSS - one abstraction layer deep for no real reason. It creates real confusion, like you see in this thread. Also, the classes-in-HTML are a mess - a tired criticism, but it’s still, like, true.

There are two problems Tailwind solves: one is maintainability, which it solves by co-locating CSS styles with HTML. Inline styles almost solve this problem, but they don’t. Tailwind does.

The second problem Tailwind solves is generating a good design system (spacing, colors, font scales) out of the box. Tailwind does this really well, well enough that I think the colors more than anything were the main driver of adoption. The maintainability is a bonus.

The problem, again, is that Tailwind is a degenerate, nonstandard solution. The correct solution to maintainability is scoped styles. Not the scoped styles in the CSS spec, which unfortunately are kind-of useless, but component-scoped styles. In Phoenix, this means scoping styles to heex templates (e.g. function components, views, liveviews, etc).

To my knowledge, the first attempt to implement this with Phoenix was the Surface project. Unfortunately, that project contains a lot of other functionality, much of which was then ported to Phoenix (heex), and I don’t think a lot of people even know about it.

Again to my knowledge, the second attempt was my own. It is actually possible to hack scoped styles on top of Phoenix components by hijacking the heex macros and extracting a <style> tag from the content. I have been using this library to build my own apps for a while now and I can confirm that the approach scales. Note that this library is not production-ready for anyone except me - in particular, the CSS parser was a proof of concept and does not emit useful error messages (and there are some other annoyances). I intend to clean it up for others to use at some point.

Importantly, corp_style (my library) also implements design systems as a set of conveniences for generating CSS variables, with inheritance. This works really well, and combined with component-scoped styles it is a worthy Tailwind replacement.

With this approach the CSS you write is real CSS, with real CSS variables. It’s easy to learn and does not pollute your source HTML (in devtools it just looks like normal CSS). I really feel this is the approach Phoenix should take down the road. It is the framework’s responsibility to implement component functionality, not delegate to Tailwind.

10 Likes