Moshe
Moshe

Reputation: 6991

Overriding Tailwind CSS Classes in a Reusable VueJS Component

I have created a VueJS button component using TailwindCSS. My goal is to provide that button component with some base styles (using tailwindcss classes), with the option to override them when need be (again, using tailwind css classes).

For example, here is a simplified version of the Button component:

// Button.vue

<template>
  <button class="bg-green-500 text-white py-2 px-4 rounded">
    Click Me
  </button>
</template>

And here is an example of my using that component in another file:

// index.vue

<Button></Button>
<Button class="bg-red-600"></Button>
<Button class="bg-blue-600"></Button>

The problem is that this only half-works. That is to say, bg-blue-600 does override the bg-green-500 that I set up as a default in Button.vue. But bg-red-600 does not override the background color (presumbably, because bg-red-600 comes earlier in the css source code.

As such, I am wondering how can I properly set this up? That is to say, how can I give the Button component some base styles (again, using tailwind css classes) while also providing the option to override those styles using tailwind css classes.

Thanks.

Upvotes: 20

Views: 15173

Answers (8)

Zack Plauch&#233;
Zack Plauch&#233;

Reputation: 4210

Tailwind-merge seems like the best answer

from my research and experience so far.

NOTE: I didn't build it in anyway, just discovered it through the Tailwind discord server.

Step 1: Install yarn add tailwind-merge

Step 2:

<template>
  <button class="text-white py-2 px-4 rounded" :class="twMerge('bg-green-500', $attrs.class)">
    Click Me
  </button>
</template>

<script setup>
import { twMerge } from 'tailwind-merge'
</script>

Whatever you want to be able to override put in the twMerge first argument string.

Then use how you'd expect, and you're done! ✅

Upvotes: 0

Simon
Simon

Reputation: 594

The tailwind-unimportant plugin for Tailwind solves this problem. It adds a variant that reduces the specificity of the component classes so that they can be overridden.

// Button.vue

<template>
  <button class="-:bg-green-500 -:text-white -:py-2 -:px-4 -:rounded">
    Click Me
  </button>
</template>
// index.vue

<Button></Button>
<Button class="bg-red-600"></Button>
<Button class="bg-blue-600"></Button>

There's also the tailwind-merge, a JS library that will de-duplicate these clashing classes.

Upvotes: 1

Unmitigated
Unmitigated

Reputation: 89234

Arbitrary variants can be used to increase the specificity of the generated selector to allow later classes to always be applied.

In this case, use [&&]:bg-blue-600 for the class name to overwrite the style for bg-green-500. To overwrite it again later, you can use another class with an increased number of ampersands (&), e.g. [&&&]:bg-blue-700.

For special cases, the !important modifier can be applied to override nearly anything else. This can be done by adding ! in front of the class name, e.g. !bg-blue-600. Use this sparingly, as it can make styles difficult to maintain and modify later on.

For an explanation of why this occurs, see the Multiple Same CSS Classes issue.

Upvotes: 1

krishnaacharyaa
krishnaacharyaa

Reputation: 24940

Use ! important operator infront of any class to override existing class.

The important option lets you control whether or not Tailwind’s utilities should be marked with !important. This can be really useful when using Tailwind with existing CSS that has high specificity selectors.


Explanation:

Tailwind in case of conflicts uses the latest className while styling (Not necessarily true all the time)

Example:

<div class="bg-black h-screen bg-green-600"></div>

Output: enter image description here

The bg-black is overridden by bg-green-600.


How to get bg-black ?

Use ! operator infront of bg-black as !bg-black

<div class="!bg-black h-screen bg-green-600"></div>

Output:

enter image description here

See also : Override tailwind-css base classes

Upvotes: 5

Sharkfin
Sharkfin

Reputation: 156

If you create a tailwind class using the @apply directive, you can add in !important to make it override the other color classes when used.

You will need to use the lang="postcss" attibute to use tailwind directives in a component.

<style lang="postcss">
.my-overriding-class{
    @apply bg-red-600 !important 
}

Upvotes: 0

Bhaskar
Bhaskar

Reputation: 1938

This is because your component attributes class on Button does not tickle down to the html button. To do this just bind the attributes to the child like so

<button v-bind="$attrs"...>

This will make all the attributes you specify on the Button (which are not props) bind to the html button.

That being said, I personally prefer making a button class using the @apply directive and reusing it across my project.

Upvotes: 0

simohamed
simohamed

Reputation: 81

As a workaround, you can use props:

<!-- Button.vue -->
<template>
  <button :class="background + ' text-white py-2 px-4 rounded'">
    Click Me
  </button>
</template>

<script>
export default {
  props: {
    background: {
      type: String,
      default: "bg-green-500",
    },
  },
};
</script>
<!-- index.vue -->
<Button background="bg-red-600"></Button>
<Button background="bg-blue-600"></Button>

Upvotes: 0

Related Questions