The fix that follows directly: write the complete class names out and select between them.
A lookup object mapping your prop values to full class strings. Every class appears literally in the file, the scanner finds all of them, and you index into the map at runtime.
Why this is better than it looks:
- It is exhaustive by construction. If your prop is typed as a union, the compiler makes you handle every case, so a new variant cannot silently produce an unstyled element.
- It is greppable. Searching for
bg-red-500finds the place it is used, which a template string breaks completely. - It documents the variants in one readable place.
The rule I apply everywhere now: never build a class name by concatenation. Not for colours, not for spacing, not for grid columns, not for widths. The moment a class is assembled from pieces you are relying on something that does not exist.
The partial version catches people too — `bg-${color}-500` is obviously broken once you know the mechanism, but so is `${base}-500`, and so is splitting a class across a line break in a way that leaves the text discontinuous.
Since you suspect you have done this elsewhere: search your source for a backtick or a plus sign near a class attribute. That finds nearly all of them in a few minutes.