GregPhx
To have 'mix phx.new --no-tailwind' to just do not use Tailwind, but still create basic CSS
Greetings Everyone!!!
A little bit of my background so it could be easier to understand where my comments are coming from, and to take them with a grain of salt…or lots of.
Background
I started coding back in 1989. A few years later I was writing code with VIM in Unix: FoxBase+ and C. So, I am very used to code on a simple and fun programming language, and in a not so fun but powerful language, hence, I am used to allocate memory when needed and freeing it when no longer needed, and yes, I still use Short integers when available: The very first computer I used had 128Kb of RAM, the Tandy Color Computer 3. Some habits are hard to break, and I really want my programs to be thin and light. I am barely starting with Elixir, Phoenix, LiveView, HTML and CSS, thus… I really see no point on using Tailwind. I started using Linux in the mid '90s because I love the freedom it provides, so I totally agree that everybody is free to choose if they want to use certain tool, or not. Everybody is free to chose their poison. No questions asked (my VERY PERSONAL point of view).
Suggestion
Could it be possible to have mix to create code like this:
# === core_components.ex ===
def modal(assigns) do
~H"""
<div
[...]
# WITH Tailwind (Hard-coded styles, I guess)
class="relative z-50 hidden"
# WITHOUT Tailwind
class="sample_modal"
# === priv/static/assets/app.css ===
/* Created on the fly WITH Tailwind */
.relative{
position: relative;
}
.z-50{
z-index: 50;
}
.hidden{
display: none;
}
/* Hard-coded WITHOUT Tailwind */
.sample_modal {
position: relative;
z-index: 50;
display: none;
}
Explanation
As of now, it seems like I am being punished for not using Tailwind.
I have a few plain text lines above my form when the put_flash is invoked (:info, or :error) because there are no styles at all, and I have no clue about what styles to use to have those lines to show up as Green/Red pop-ups with CSS.
Either, 1) I will have to study what all those Tailwind classes to know what CSS they are using in order to replicate the basic behavior, or 2) I will have to create another project using Tailwind to get all those classes and then gather the CSS needed to achieve the basic behavior.
Both cases, as I mentioned before, seem like I am being punished for not using Tailwind. As far as I understand the parameter is --no-tailwind, not --no-css.
Best regards,
Greg
Marked As Solved
josevalim
Agreed. The built-in CSS for --no-tailwind should cover core components, phx.gen.auth and phx.gen.live. Let’s revisit it later!
Also Liked
garrison
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.
steffend
This is included in Augment Tailwind with DaisyUI by SteffenDE · Pull Request #6123 · phoenixframework/phoenix · GitHub. Instead of getting an unstyled application apart from the home page with --no-tailwind, people will now get a fully styled app: phoenix/installer/templates/phx_static/default.css at a37b9179e7ed13b1c367fd9bf9f1a6847a01faa0 · phoenixframework/phoenix · GitHub.
While this is not “basic” CSS - it’s still a very large file created by Tailwind + daisyUI - it is a lot better than no style and it’s basically the “just make it work” approach suggested by @GregPhx.
garrison
For the record I agree with you, and I think defaulting to Tailwind was a mistake which will have to be rectified some day.
But with that said, the default components are provided mainly as an example to get started. A lot of people are using Tailwind, so they wrote the “example” components in Tailwind.
You can simply remove the tailwind classes and style the components yourself, or write your own using them as an example. Personally, the first thing I do in a new Phoenix project is nuke core_components.ex and import my own ![]()
Nearly all of Tailwind’s classes have very obvious 1:1 mappings with CSS, down to the name - this probably won’t be as difficult as you think. Their docs are also very clear.







