Wierd tailwind class orderings

Hi,
i was trying the button in core_components.ex which accepts a class assign.
<.button class=“bg-yellow-400”>click</.button> should result in a yellow button that overrides the default bg-zinc-900 but it didn’t. picture below is a screenshot of page with devtools open. as you can see bg-yellow-400 is appended at the end of button classes.


as shown in developer tools panel, bg-yellow-400 is on line 1772 of app.css file but the bg-zinc-900 is on line 1791 and overrides it so button color does not change.

but if i change the background to bg-yellow-300 it works as expected and button changes color as shown in screenshot below.


as show in developer tools panel, bg-yellow-300 happens later in app.css file on line 1806 and overrides bg-zinc-900 on line 1791.
can somebody explain why this behavior happens? how to fix it?

It happens because the order of classes in the class doesn’t affect style precedence, but the position of the declaration in the CSS code does. If you specify multiple background classes whichever is defined last in the CSS is the one applied.

The solution is to make the component only output one background class. For example you could add a separate attr and change the class list based on what’s passed in, something like this:

attr :type, :string, default: nil
attr :color, :string, default: "zinc", values: ["zinc", "yellow"]
attr :class, :string, default: nil
attr :rest, :global, include: ~w(disabled form name value)

slot :inner_block, required: true

def button(assigns) do
  ~H"""
  <button
    type={@type}
    class={[
      "phx-submit-loading:opacity-75 rounded-lg py-2 px-3",
      if @color == "zinc" do
        "bg-zinc-900 hover:bg-zinc-700"
      end,
      if @color == "yellow" do
        "bg-yellow-400 hover:bg-yellow-300"
      end,
      "text-sm font-semibold leading-6 text-white active:text-white/80",
      @class
    ]}
    {@rest}
  >
    <%%= render_slot(@inner_block) %>
  </button>
  """
end
4 Likes

thanks for reply,
other colors when appended to class attribute always appear later in css file. it feels like the default behavior should be if a tailwind class appears later in class attribute, should be used and override the others, which i think it is as the experience i had when working with tailwind. in the example above if i use !bg-yellow-400 it actually works and button goes bg-yellow-400.
im not expert in tailwind but this feel like a bug to me.

It is not a bug, that’s how CSS classes works.

What you can do is use a library that checks and merges tailwind attributes so so the last one will be applied.

Here is one of them Turboprop - Toolkit to create accessible component libraries

2 Likes