DEV Community

Cover image for How to merge Tailwind class in Elixir Phoenix
Dung Nguyen
Dung Nguyen

Posted on

How to merge Tailwind class in Elixir Phoenix

Problem

I am working on an open source project OrangeCMS using Phoenix LiveView. I am building some reusable components which supports custom class. But many time custom class conflict with default class and I didn't get expected result.

For example:

attr :class, :string, default: nil
slot :inner_block, required: true
def my_component(assigns) do
  ~H"""
   <div class={["bg-green-500", @class]}>
    <%= render_slot(@inner_block) %>
   </div>
  """
end
Enter fullscreen mode Exit fullscreen mode

and use it

<.my_component class="bg-red-500"> HELLO </.my_component>

The result is not red-500 as you might expected.

Solution

I searched for a solution, and I found tailwind-merge which is written in JavaScript. Basically it finds conflicted classes and resolve the conflict. For example:

twMerge('px-2 py-1 bg-red hover:bg-dark-red', 'p-3 bg-[#B91C1C]')
// → 'hover:bg-dark-red p-3 bg-[#B91C1C]'
Enter fullscreen mode Exit fullscreen mode

I was thinking of porting this library to Elixir. But first, I searched on hex.pm and Surprising. I found two packages that support merging tailwind classes: twix and tails

First, I try Twix but it doesn't support custom color classes and raise exception.

Then I try Tails , and with some little configuration, it works perfectly.

  1. Add Tails to your dependencies

{:tails, "~> 0.1.5"}

  1. Add custom colors.json files to /assets/ or /priv directory
{
  "primary": "orange",
  "secondary": "green"
}
Enter fullscreen mode Exit fullscreen mode
  1. Add Tails config
config :tails, colors_file: Path.join(File.cwd!(), "assets/colors.json")
Enter fullscreen mode Exit fullscreen mode
  1. Update code

Wrap class list with Tails.classes

class={Tails.classes(["bg-green-500", @class])}

attr :class, :string, default: nil
slot :inner_block, required: true
def my_component(assigns) do
  ~H"""
   <div class={Tails.classes(["bg-green-500", @class])}>
    <%= render_slot(@inner_block) %>
   </div>
  """
end
Enter fullscreen mode Exit fullscreen mode

Conclusion

Thank to *Zach Daniel *, it's now easier for us to resolve tailwind class conflict in Elixir. And before roll out my own solution, I should take a second to search on Hex.pm , it's amazing that most of what I need was already implemented by Elixir community. Send my regards to all of those who spend their precious hours to make my life easier.

Top comments (1)

Collapse
 
snowyang profile image
Snow Yáng

Thanks, really good share!