Tutorial
Add Tailwind HTML Generators in Phoenix
This post was updated 04 Feb - 2022
Let's say that you have a project set up with Tailwind. Or even if you dont, let say you just want to customise the code build in HTML generators generate.
But since I do use Tailwind, I want to call my html generator:
mix tailwind.gen.html ..
instead of mix phx.gen.html ..
STEP 1
A good place to start is to copy the actual generator from the files that was created when the project was generated.
mkdir -p lib/mix/tasks
cp deps/phoenix/lib/mix/tasks/phx.gen.html.ex lib/mix/tasks/tailwind.gen.html.ex
Then open the file and rename the module to
Mix.Tasks.Tailwind.Gen.Html
And in the file, we also need to change all instances of `phx` to `tailwind`.
AS you can see in the copy_new_files
method, it expects the new files to be used of the generator to be in the folder: priv/templates/tailwind.gen.html
.
The commands to create the folder and copy the generator files over are:
mkdir -p priv/templates/tailwind.gen.html
cp -a deps/phoenix/priv/templates/phx.gen.html/. priv/templates/tailwind.gen.html
If you managed to to this without mistakes you should be able to run:
mix compile && mix help | grep 'tailwind'
If everything works, you should see something like:
STEP 2
Next step is little of a hot topic. I prefer extracting some of the most atomic html elements to the css file and not only use the classes inline in the DOM.
These would be cards, inputs and buttons. And the reason is that its important that they look similar across the site.
I also am of the opinion that the class names to use would be Bootstrap compatible. So I would name it .card
, .btn .btn-primary
, form-control
etc. That makes it simple for other that are most used to Bootstrap to navigate the code.
So, once more I need to edit lib/mix/tasks/tailwind.gen.html.ex
inside the defp inputs
and append the class in each case statement.
, class: "form-control"
Then when it comes to the templates, I can go through them and edit them to whatever I want. In priv/templates/tailwind.gen.html/show.html.eex
I want to but the content in a card-div with a header.
So the original code:
<h1>Show <%= schema.human_singular %></h1><ul>
<%= for {k, _} <- schema.attrs do %>
<li>
<strong><%= Phoenix.Naming.humanize(Atom.to_string(k)) %>:</strong>
<%%= @<%= schema.singular %>.<%= k %> %>
</li>
<% end %>
</ul><span><%%= link "Edit", to: Routes.<%= schema.route_helper %>_path(@conn, :edit, @<%= schema.singular %>) %></span>
<span><%%= link "Back", to: Routes.<%= schema.route_helper %>_path(@conn, :index) %></span>
And the updated template after the changes:
<div class="card">
<div class="card-header flex">
<h5 class="mb-0 flex-1">Show <%= schema.human_singular %></h5>
<span class="text-sm mr-1"><%%= link "Edit", to: Routes.<%= schema.route_helper %>_path(@conn, :edit, @<%= schema.singular %>) %></span>
<span class="text-sm"><%%= link "Back", to: Routes.<%= schema.route_helper %>_path(@conn, :index) %></span>
</div>
<div class="card-body">
<ul>
<%= for {k, _} <- schema.attrs do %>
<li class="mb-2">
<strong><%= Phoenix.Naming.humanize(Atom.to_string(k)) %>:</strong>
<%%= @<%= schema.singular %>.<%= k %> %>
</li>
<% end %>
</ul>
</div>
</div>
Since I now references some classes, I need to add them in assets/css/app.css
. The custom css needs to go between components
and utilities
@tailwind base;
@tailwind components;
// Add custom css here ...
@tailwind utilities;
The good thing is that you can still use Tailwind classes like this:
css
.btn {
@apply inline-block font-normal text-center px-3 py-2 leading-normal text-base rounded cursor-pointer;
}.btn-primary {
@apply text-white bg-blue-600;
}.btn-primary:hover {
@apply text-white bg-blue-700
}