Home > database >  Tailwind color not working on dynamic classes Vue Vite
Tailwind color not working on dynamic classes Vue Vite

Time:12-30

First time Im using tailwind and I can't figure out why colors are not working. This is a fresh install of Laravel Jetstream which comes with Tailwind, Vue3, Vite & Inertia.

seems like the relevant styling is not imported from tailwind if classes are added dynamically.

Here's some basic component

<template>
    <div :  role="alert">
        <p><slot name="headline"></slot></p>
        <p  v-if="slots.error"><span >Message:</span><slot name="error"></slot></p>
        <div  v-if="slots.info"><slot name="info"></slot></div>
    </div>
</template>
<script setup>
    import { useSlots } from 'vue'
    const slots = useSlots()
</script>
<script>
export default {
    name: 'Alert',
    props: {
        color: {type: String, default: 'red'}
    },
    computed: {
        style() {
            return `bg-${this.color}-100 border-${this.color}-500 text-${this.color}-700`
        }
    }
    
}
</script>

and using something like this does not have any color related styling although the class is there

<Alert color="orange" >
    <template #headline>Test</template>
</Alert>

but if the dynamic classes are also specified somewhere in the same page then everything works.

i.e.

<div ></div>
<Alert color="orange" >
        <template #headline>Test</template>
</Alert>

CodePudding user response:

Is it recommended to use dynamic class in tailwind ?

No, Using dynamic classes in tailwind-css is usually not recommended because tailwind uses tree-shaking i.e any class that wasn't declared in your source files, won't be generated in the output file.

Hence it is always recommended to use full class names

According to Docs

If you use string interpolation or concatenate partial class names together, Tailwind will not find them and therefore will not generate the corresponding CSS

Isn't there work around ?

Yes, As a last resort, Tailwind offers Safelisting classes.

Safelisting is a last-resort, and should only be used in situations where it’s impossible to scan certain content for class names. These situations are rare, and you should almost never need this feature.

In your example,you want to have 100 500 700 shades of colors. You can use regular expressions to include all the colors you want using pattern and specify the shades accordingly .

Note: You can force Tailwind to create variants as well:

In tailwind.config.js

module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}',
  ],
  safelist: [
    {
      pattern: /bg-(red|green|blue|orange)-(100|500|700)/, // You can display all the colors that you need
      variants: ['lg', 'hover', 'focus', 'lg:hover'],      // Optional
    },
  ],
  // ...
}
EXTRA: How to automate to have all tailwind colors in the safelist
const tailwindColors = require("./node_modules/tailwindcss/colors")
const colorSafeList = []

// Skip these to avoid a load of deprecated warnings when tailwind starts up
const deprecated = ["lightBlue", "warmGray", "trueGray", "coolGray", "blueGray"]

for (const colorName in tailwindColors) {
  if (deprecated.includes(colorName)) {
    continue
  }

  // Define all of your desired shades
  const shades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900]

  const pallette = tailwindColors[colorName]

  if (typeof pallette === "object") {
    shades.forEach((shade) => {
      if (shade in pallette) {
       // colorSafeList.push(`text-${colorName}-${shade}`)  <-- You can add different colored text as well 
        colorSafeList.push(`bg-${colorName}-${shade}`)
      }
    })
  }
}

// tailwind.config.js
module.exports = {
  safelist: colorSafeList,                      // <-- add the safelist here
  content: ["{pages,app}/**/*.{js,ts,jsx,tsx}"],
  theme: {
    extend: {
      colors: tailwindColors,
    },
  },
  plugins: [],
}

CodePudding user response:

Tailwind CSS is compiled to your code to reduce CSS file size. If you didn't hard code classes, the compiler won't know you need them.

Yeah, it scans classes and adds classes with styling to a CSS file. So if you want to have dynamic colors, make sure all colors you will use to hard code them somewhere, or they won't be added to CSS file.

CodePudding user response:

Tailwind parses your files to know which styles to keep.
Any unused classes are not exported to the output CSS file.

You mentioned

but if the dynamic classes are also specified somewhere in the same page then everything works.

This indicates your environment is not set up correctly.

Your tailwind.config.js file should look like this,

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./js/**/*.js",
    "index.html",
    "404.html"
  ],//https://github.com/tailwindlabs/tailwindcss/discussions/8651#discussioncomment-2965483
  theme: {
    extend: {},
  },
  plugins: [],
}

Tailwind will parse all files matching the patterns in content.
So, you should add ./**/*.vue or whatever is required depending on your directory structure to it.

Refer to:

  1. https://tailwindcss.com/docs/content-configuration#pattern-recommendations
  2. https://jetstream.laravel.com/2.x/concept-overview.html#tailwind
  3. https://github.com/tailwindlabs/tailwindcss/discussions/8651#discussioncomment-2965483

From the Laravel Jetstream Docs,

During installation, Jetstream will scaffold your application's integration with the Tailwind CSS framework. Specifically, a postcss.config.js file and tailwind.config.js file will be created. These two files are used to build your application's compiled CSS output. You are free to modify these files as needed for your application.

CodePudding user response:

This was relatively an easy fixed, it was mentioned in here to avoid constructing class name dynamically https://tailwindcss.com/docs/content-configuration#dynamic-class-names

so, in the computed style I just specify full class name conditionally with all the possible values

changed from this.

style() {
    return `bg-${this.color}-100 border-${this.color}-500 text-${this.color}-700`
}

to this

style() {
    const styles = {
        default : 'bg-cyan-100 border-cyan-500 text-cyan-700',
        red : 'bg-red-100 border-red-500 text-red-700',
        orange: 'bg-orange-100 border-orange-500 text-orange-700',
        green: 'bg-green-100 border-green-500 text-green-700',
        blue: 'bg-blue-100 border-blue-500 text-blue-700',
    }
    return styles[this.color] ?? styles.default
}

now everything works perfectly

  • Related