Search code examples
data-bindingvuejs3

Vue 3 with Tailwind using v-bind:class shows classes in html element but not render while style works correctly


I am new to Vue and I'm trying to bind multiple classes in a v-for loop from a const array of object imported from a file.js. But the trick I'm trying is to import const and than return classes from method that evaluates one property of object looped. I've tried all ways, methods, computed, setup, onMounted, beforeMount, but even if i can see my classes in html they aren't rendered in styles section of DevTools. The only way that works is to v-bind:style instead of class. Or just put exact classes in my const array object as a property but I prefer to avoid this. It seems to save something in cache, but i have tried to delete and to lunch application in hidden mode but it won't works Is there someone who can help me to understand and maybe to resolve? Thanks in advance

this is my actual code:

<template>
    <div id="cv" class="tp3-flex md:tp3-grid md:tp3-grid-cols-[repeat(27,_minmax(0,_1fr))] md:tp3-grid-rows-[repeat(6,_minmax(0, 5rem))] tp3-justify-center tp3-content-center tp3-justify-items-center tp3-mx-auto tp3-p-2 tp3-bg-cyan-500 tp3-text-blue-50">

        <div v-for="(softSkill, index) in softSkills" :key="`softSkill-${index}`"
        class="tp3-flex tp3-w-20 tp3-h-20 -tp3-rotate-45 tp3-rounded-full tp3-rounded-tr-none tp3-justify-center tp3-items-center tp3-bg-slate-400 tp3-opacity-70 tp3-mb-4 tp3-mt-4 tp3-shadow-md tp3-overflow-hidden"
        v-bind:class="posCols(softSkill)">
            <div class="tp3-rotate-45">
                <span v-html="softSkill.text"></span>
            </div>
        </div>

    </div>
</template>

<script>
import {softSkills} from "@/assets/skills/softSkills";

export default {
    name: "ComponentSoftSkills",
    data(){
        return{
            softSkills: null
        }
    },
    beforeMount() {
        this.softSkills = softSkills;
    },
    methods: {
        posCols(softSkill){
            console.log(softSkill);
            return ' tp3-col-start-['+softSkill.col+'] tp3-col-end-['+(softSkill.col+1)+']';
        }
    }
}
</script>

<style lang="css" scoped>
</style>


and my file.js is:

export const softSkills = [
    {text:`skill 1`, col:1, row:1},
    {text:`skill 2`, col:5, row:1},
    {text:`skill 3`, col:2, row:2},
    {text:`skill 4`, col:15, row:1},
]

enter image description here

enter image description here


Solution

  • I have a suspicion that this might be due to your tailwind setup.

    Because the classes are assigned dynamically and tailwind (depending on the configuration) is only making classes available that it can find during compilation. So the classes, even though you see them populated correctly, are not made available through tailwind. simply put, when tailwind scans the code, it doesn't recognize md:tp3-grid-cols-[repeat(27,_minmax(0,_1fr))] or tp3-col-start-[${softSkill.col}] as a valid class name and does not generate the class for it.

    Assuming this is the issue and not knowing the exact version on configuration can't give an exact solution, but here are some tips for it.

    Instead of using dynamic class names, define all the class names and assign dynamically

    so instead of using tp3-col-start-[${softSkill.col}] tp3-col-end-[${(softSkill.col+1)}]

    you could make sure all possible classes are clear and accessible by the tailwind parser:

    let colClass = `tp3-col-start-[0] tp3-col-end-[1]`;
    if(softSkill.col === 1) colClass = "tp3-col-start-[1] tp3-col-end-[2]";
    if(softSkill.col === 2) colClass = "tp3-col-start-[2] tp3-col-end-[3]";
    if(softSkill.col === 3) colClass = "tp3-col-start-[3] tp3-col-end-[4]";
    if(softSkill.col === 4) colClass = "tp3-col-start-[4] tp3-col-end-[5]";
    if(softSkill.col === 5) colClass = "tp3-col-start-[5] tp3-col-end-[6]";
    // ...etc
    

    this is obviously very verbose, but the classes are clearly defined in the code, so tailwind can find them when scanning your code.

    Safelisting classes

    using safelisting of classes is another option. Instead of having the code in your js, you would have it in the configuration

    // tailwind.config.js
    module.exports = {
      // ...other stuff
      safelist: [
        'tp3-col-start-[0]',
        'tp3-col-start-[1]',
        'tp3-col-start-[2]',
        'tp3-col-start-[3]',
        'tp3-col-start-[4]',
        'tp3-col-start-[5]',
        // ...etc
        'tp3-col-end-[1]',
        'tp3-col-end-[2]',
        'tp3-col-end-[3]',
        'tp3-col-end-[4]',
        'tp3-col-end-[5]',
        // ...etc
      ],
    }
    

    there's also a way to use regex, which might look something like this:

    // tailwind.config.js
    module.exports = {
      // ...other stuff
      safelist: [
        {
          pattern: /tp3-col-start-[(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15)]/,
          variants: ['sm', 'lg'], // you can add variants too
        },
        {
          pattern: /tp3-col-end-[(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16)]/,
        },
      ],
    }
    

    you can read more about safelisting here safelisting-classes