Most answers related to TailwindCSS v3 apply to this question, but the guideline has not changed: Do not use dynamically class names!
You can find the official explanation in the documentation. I won't repeat the v3 examples here, as the following answers are already good references for that.
In v4, however, the possibilities have expanded and safelisting has changed. That's what I'd like to explain in detail.
Safelist
Specifically, the patterns in them answer can be written like this in v4:
@import "tailwindcss";
@source inline "text-{red,green,blue}-700";
@source inline "bg-{red,green,blue}-300";
And by combining bg, text and hover: variant from 50 to 950, the example would look like this:
@import "tailwindcss";
@source inline "{hover:,}{text,bg}-{red,green,blue}-{50,{100..900..100},950}";
Static theme variables
In addition to all this, a so-called static theme declaration option has been introduced. It doesn't generate the utilities themselves but places the corresponding variables into the generated CSS, making it easier to use those variables more dynamically even without utilities:
@import "tailwindcss";
@theme static {
--color-primary: var(--color-red-500);
--color-secondary: var(--color-blue-500);
}
Now, if you haven't used the primary color in any form - for example, neither bg-primary nor text-primary nor in any other way - then originally var(--color-primary) would not be included in the generated CSS by @theme { ... }. However, due to the @theme static { ... } static import, it still gets included.
import React from "react";
type ExampleProps = {
type: "primary" | "secondary";
};
export default function Example({ type }: ExampleProps) {
return (
<p style={{ color: `var(--color-${type})` }}>
This text uses {type} color
</p>
);
}
<Example type="primary" />
<Example type="secondary" />
Important: text-${type} class name is still invalid! Keep in mind that the examples use CSS variables, which work independently of TailwindCSS.
And extending the previous example full of variables, I'll move on to using TailwindCSS classes that don't take a direct value, but instead reference a variable name. This way, the variable name itself is static and never changes, while the value carried by the variable can still be manipulated with JS.
For example, instead of bg-sky-500 you can use bg-(--color-sky-500). Or you can declare your own variable like bg-(--currentcolor) and then set the actual value of the --currentcolor variable via the style attribute: --currentcolor: var(--color-primary); (which I marked earlier as static).
Example
Here's an incorrect example (DO NOT USE):
{/* IMPORTANT: DO NOT USE IT, this is just an example of incorrect usage */}
<div
class={"
col-start-${colStart} col-end-${colEnd}
row-start-${rowStart} row-end-${rowEnd}
...
"}
>...</div>
What the correct approach could look like.
You can avoid using Tailwind utilities - it's not wrong to solve something with native CSS, and this way the value can be dynamic.
<div
class={"..."}
style={{
gridColumnStart: colStart,
gridColumnEnd: colEnd,
gridRowStart: rowStart,
gridRowEnd: rowEnd
}}
>...</div>
Or give the utilities a reference to a CSS variable. Then, in the style, declare the appropriate variables instead of using property.
<div
class={"
col-start-(--col-start) col-end-(--col-end)
row-start-(--row-start) row-end-(--row-end)
...
"}
style={{
'--col-start': colStart,
'--col-end': colEnd,
'--row-start': rowStart,
'--row-end': rowEnd
}}
>...</div>