How to create components in Phoenix?

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),
        px-4 py-2
        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:

<td class="whitespace-nowrap px-3 py-4 text-base text-gray-900"><%= contact.firstName %></td>

Is there a way to encapsulate these into components so that I don’t have to repeat the styles? Something like:

<LinkButton to={Routes.contact_path(@conn, :new)} />
<TableCell><%= contact.firstName %></TableCell>

It would be something like this:

defmodule MyAppWeb.Table do
  use Phoenix.Component

  def head(assigns) do

  def cell(assigns) do
    <td class="whitespace-nowrap px-3 py-4 text-base text-gray-900">
      <%= render_slot(@inner_block) %>

And you would use it as such in your HEEX: (assuming MyAppWeb.Table is aliased)

  <Table.head items={["First Name", "Age", ...]} />
  <%= for contact <- @contacts do %>
    <Table.cell><%= contact.first_name %></Table.cell>
    <Table.cell><%= contact.age %></Table.cell>
  <% end %>

You could also import the module as suggested here :slight_smile:

defmodule MyAppWeb do
  defp view_helpers do
    quote do
      import MyAppWeb.ButtonComponent

Furthermore I’d recommend using semantic class names (.button) in combination with Tailwind’s @apply or theme(...) over utility classes for two reasons:

  1. 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)
  2. source code is a lot easier to read (especially when you have a lot of conditionals)

See my explanation here: "Petal Components" package - a set of Tailwind styled components written in HEEX - #45 by thomasbrus

Thanks @LostKobrakai, @tomkonidas & @thomasbrus for your suggestions. For now, I am going with @tomkonidas’s suggestion because it looks simpler to me. Later I can try @thomasbrus’ suggestions.