Open brandonmcconnell opened 7 months ago
I noticed this, and yeah it's a tricky problem.
Variant chaining is the built-in adequate solution IMO. signal:bg-blue-100 signal:signal/one:bg-blue-200 signal:signal/one:signal/two:bg-blue-300
would override background color as expected. This is how people currently use group-hover:group-focus
, and it's intuitive once you understand that CSS class usage order doesn't correlate with cascade order.
Currently, the priority of conflicting signal-triggered styles relies solely on the order in which they are processed and appear in the output stylesheet. This lack of proper prioritization results in variable results when working with conflicting styles and makes using them for the same style unreliable.
It's an edge case, and even Tailwind CSS core doesn't support built-in prioritization beyond the
!
symbol for importance, but they don't need to for this case because Tailwind CSS leverages the built-in specificity algorithm for style prioritization.Tailwind CSS does, however, deal with something similar with their media query sorting internally. A similar convention could work here. I see a couple of options here:
A more straightforward solution could be to order the signals based on the number of variants used to trigger them. In the example below, the container query for each signal would be ordered based on the specificity of the condition used when declaring it.
One issue with this approach that is core to the principle of Signals for Tailwind CSS is that signals must be trigger-able in multiple ways and places, so it might be unclear which usage is the most specific in certain instances. Even with that approach, certain signals might require different specificities in different places.
This option would be the closest to how a natural CSS solution would work, similar to how
group
works, and this should maintain a 1:1 complementary relationship to that as much as possible.One last missing step that may ultimately solve this issue is to create a new media query not only per name but also per declaration, allowing each declaration to be uniquely sorted based on its specificity.
Another option could be to use the modifier syntax as a manual prioritization system instead, so someone could use any of these:
signal:vader
(specificity defaults to0
)hover:signal/1:obiwan
peer-checked:signal/2:yoda
peer-checked:hover:signal/3:macewindu
With this solution, I would expose signals as BOTH a variant and a utility, but both would have the same functionality of setting up the signal. Then, to consume a signal, you would use a different accompanying utility, perhaps
effect
as suggested by @AlexVipond in #1. This would solve the issue, but I don't love this solution to the problem and how it places the full burden of manual specification into the hands of the users. (I might still rename the variant toeffect
though to better align with the prior art behind signals in JS)tailwind-merge
(or similar)Action items
For now, with this all at front of mind, I think the ideal solution would be Option 1, specifically the idea to set up a new container query per usage/unique selector sorted based on that selector's specificity.
:where
zeroes out the specificity of a given selector, and that should be reflected here as well. Maybe I can get the final selector back from Tailwind's engine and use a 3rd party lib to determine specificity.