Tailwind, CoreComponents, button colors vanishing, and (maybe) caching

TL;DR: I feel that I am doing something really wrong, but don’t know what it is. <.button> color overrides using standard colors seem very Schrodinger to me, they come and they go, and it’s not clear why.

TL;DR working hack I’ve got a solution that means that button colors work by cloning the CoreComponents button function into uncolored_button, and removing the “bg-zinc-900 hover:bg-zinc-700” terms from the class list. This is a hacky work around, but good enough for production.

Problem

I needed to set background colors in the <.button> tag for a state machine driven interaction, graying out buttons, using something like “bg-gray-300”, changing button text etc

Due to the nature of the relatively complex business logic that I wanted to make explicit in the template, it was easier to repeat the tags in a set of HEEX <%= if %> structures than using {@variable} interpolation.

Challenge

Whenever I did a mix clean as part of a release process, the button backgrounds would no longer work.

If I changed the specific <.button> class to “bg-red-400” or something, they worked again. Until they didn’t and everything reverted to “bg-zinc-900”.

Tailwind class strings

I had assumed that Tailwind class attributes were like CSS, which is “last defined, wins”. Apparently not the case from doing some Internet research, which is genuinely a bit of a surprise.

Web inspection showed my bg-red-400 or whatever at the end, but it was bg-zinc-900 that seemed to happen.

Reversing the class list in <.button>

I tried putting @class in front of the CoreComponents defined class attributes list but that only sometimes worked.

Working hack solution

See above. It works, but isn’t very satisfying.

Questions

  1. Why does this happen?
  2. What - if any - relation does this have with tailwind interpolation?
  3. How can I fix my styled use of CoreComponents to actually work reliably?

Thanks!

  1. Why does this happen?

Because “I had assumed that Tailwind class attributes were like CSS, which is “last defined, wins”.” is incorrect. It’s "last defined in the CSS file wins and that depends on Tailwind’s internal logic. Your “works until it doesn’t” situation specifically happens because:

  1. You first start the dev server, Tailwind generates existing classes.
  2. You add a new class with a new color while the dev server is running. Tailwind appends the new class to the CSS file. Now it’s last defined wins.
  3. You clean and rebuild from start. Now your class added in 2 will be put somewhere else in the file, not at the end anymore.

In particular, colors are defined alphabetically in the resulting stylesheet, and zinc is after red.

  1. How can I fix my styled use of CoreComponents to actually work reliably?

Wrap your component’s class attribute with Turboprop Merge (disclaimer: I built it) which removes conflicts like these and changes it to be like you expected: last defined wins.

1 Like

Thanks! That’s great, it addresses the Schrodinger effects I see, which was driving me mad…!

Would you suggest just wrapping every class attribute list in CoreComponents through Turboprop Merge to get results that match developer intent?