Using CSS calc() with TailwindCSS and JS variables
Asked Answered
S

2

7

In a sentence: Why does calculations with JS variables does not apply any style using TailwindCSS v3?

I am using VueJS for my project, and this example works as expected as it simply applies calc as string:

...
<div class="w-[calc((100%-12rem)*2/3)]">
...

While this doesn't (there are JS variables involved):

...
<div :class="`w-[calc(${props.languages.length * 1.25 + 3}rem)]`">
...

When I inspect the console, I can see HTML with the correct class:

...
<div class="flex w-[calc(14.25rem)]"
...

... but styles are not applied. Any ideas? What am I doing wrong? I think this is a very powerful feature as it lets you dynamically style your HTML based on underlying data, but I can't make it work although I think am so close.

Thanks in advance.

Skepful answered 4/9, 2023 at 11:34 Comment(5)
I'm not sure, but if you're doing the calculation in JavaScript wouldn't it be "easier" to simply use class=`flex w-[${calculation-result}]`, leading to - from your example - class=`flex w-[14.25rem]`(edited after checking the docs).Stockmon
Thanks @DavidThomas, I am using VueJS and have to prepend : to the class attribute for Vue to consider it as a "JS string". But I am basically doing what you suggest.Skepful
Fair enough, I admit that I didn't even notice the prepended : character; given your comment I'm rather glad that I didn't, since I'd probably have raised that as an issue (not knowing that Vue was in use). I have added the vue.js to the question so others are more aware, feel free to edit it back out though.Stockmon
Just edited the question to add the VueJS dependency.Skepful
Yes, just wrote an answer with my own research and results. Thanks anyway!Skepful
S
4

I finally found the cause: Tailwind's JIT, which is enabled and working by default in TailwindCSS v3.

Here is the interesting part: they say not to construct class names dynamically, which is precisely what I was trying to do.

So I finally followed their recommendation (see this very useful v2 docs link) and bypassed Tailwind for one time, directly using a style attribute to set the width of my element like this:

<div :style="`width: ${props.languages.length * 1.25 + 3}rem;`">

Thanks anyway ;)

Skepful answered 4/9, 2023 at 12:14 Comment(2)
@dogukan's answer is much better. It builds a dynamic class, but it uses CSS variables, so the Tailwind CSS compiled code will reference the CSS variable. You can also manipulate the CSS variable at runtime with JavaScript, and the class will not change.Roughspoken
However, what you've shared is useful. The problem with dynamically declared class names using JS variables is that, during native CSS compilation, the variable's value is unknown, which can be practically anything. Therefore, using JS variables in dynamic class names, as you mentioned, is incorrect and should not be followed. Great research work!Roughspoken
B
4

Do this instead:

<script src="https://cdn.tailwindcss.com"></script>

<div id="el" class="w-[calc(var(--languages-length)_*_1.25rem_+_3rem)] h-10 bg-red-300"></div>

<script>
el.style.setProperty('--languages-length', 6);
</script>

Equivalent in Vue:

<div 
 class="w-[calc(var(--languages-length)_*_1.25rem_+_3rem)] h-10 bg-red-300" 
 :style="{ '--languages-length': props.languages.length }"
></div>
Benignant answered 4/9, 2023 at 12:12 Comment(0)
S
4

I finally found the cause: Tailwind's JIT, which is enabled and working by default in TailwindCSS v3.

Here is the interesting part: they say not to construct class names dynamically, which is precisely what I was trying to do.

So I finally followed their recommendation (see this very useful v2 docs link) and bypassed Tailwind for one time, directly using a style attribute to set the width of my element like this:

<div :style="`width: ${props.languages.length * 1.25 + 3}rem;`">

Thanks anyway ;)

Skepful answered 4/9, 2023 at 12:14 Comment(2)
@dogukan's answer is much better. It builds a dynamic class, but it uses CSS variables, so the Tailwind CSS compiled code will reference the CSS variable. You can also manipulate the CSS variable at runtime with JavaScript, and the class will not change.Roughspoken
However, what you've shared is useful. The problem with dynamically declared class names using JS variables is that, during native CSS compilation, the variable's value is unknown, which can be practically anything. Therefore, using JS variables in dynamic class names, as you mentioned, is incorrect and should not be followed. Great research work!Roughspoken

© 2022 - 2024 — McMap. All rights reserved.