I am using tailwind with Phoenix framework. Currently I have to repeat classes for components like buttons, links, tables etc. to maintain the look & feel.
For example, here’s a link that looks like a button:
<%= link "New Contact",
to: Routes.contact_path(@conn, :new),
class:
"inline-block
px-4 py-2
rounded-lg
shadow-md
bg-gray-800
hover:bg-gray-700
text-white
focus:outline-none focus:ring focus:ring-offset-2 focus:ring-primary-main focus:ring-opacity-50
uppercase tracking-wider font-semibold text-sm"
%>
Here’s an example of a table cell with the look that I want:
defmodule MyAppWeb.Table do
use Phoenix.Component
def head(assigns) do
~H"""
...
"""
end
def cell(assigns) do
~H"""
<td class="whitespace-nowrap px-3 py-4 text-base text-gray-900">
<%= render_slot(@inner_block) %>
</td>
"""
end
And you would use it as such in your HEEX: (assuming MyAppWeb.Table is aliased)
<div>
...
<Table.head items={["First Name", "Age", ...]} />
<%= for contact <- @contacts do %>
<Table.cell><%= contact.first_name %></Table.cell>
<Table.cell><%= contact.age %></Table.cell>
...
<% end %>
...
</div>
You could also import the module as suggested here
defmodule MyAppWeb do
defp view_helpers do
quote do
import MyAppWeb.ButtonComponent
end
end
end
Furthermore I’d recommend using semantic class names (.button) in combination with Tailwind’s @apply or theme(...) over utility classes for two reasons:
you won’t run into specificity issue once you try to pass a class to the component (<.button class="p-2">... ← this could otherwise conflict with a p-3 utility class within the component)
source code is a lot easier to read (especially when you have a lot of conditionals)