withPrefix
The escape hatch for variants tailess does not model as keys — supports-[…], has-[…], group-[.open] and anything else Tailwind accepts.
Any variant Tailwind accepts
withPrefix takes a variant prefix without its colon and a set of classes, and puts the prefix in front of every class in the set. There is no list of accepted prefixes — whatever Tailwind parses as a variant works here.
withPrefix("supports-[display:grid]", "grid"); // → "supports-[display:grid]:grid"withPrefix("has-[:checked]", "bg-blue-50"); // → "has-[:checked]:bg-blue-50"withPrefix("group-[.open]", "rotate-90"); // → "group-[.open]:rotate-90"The result is a plain class string, so it goes straight into an ss group, a cn call or a bare className.
Prefer a key when one exists
The 149 keys ss accepts already cover breakpoints, max-width ranges, pseudo-classes, pseudo-elements, media and feature queries, direction and transition, the two descendant selectors, and group-* / peer-* states. Reach for a key first: it is autocompleted, checked by the compiler, and it nests.
What is deliberately missing from that list is anything carrying a value of its own — data-*, aria-*, supports-*, has-*, not-*, an arbitrary min-[…]. The first two have their own helpers in data and aria; withPrefix is what covers the rest.
The prefix must be a literal
withPrefix assembles the class at runtime, so Tailwind never sees the finished class in your source and the build plugin has to supply it. One line of setup covers this helper along with every other one.
The scanner reads both arguments as literals at the call site. A computed prefix is not in the source to read, so there is nothing to enumerate and the class lands on the element with no rule behind it.
withPrefix(dynamicPrefix, "grid"); // a computed prefixWhen the prefix genuinely has to vary, write the finished classes into a match lookup instead — it needs no build integration at all, because every class in it is already a literal.
You will hear about a missing plugin