dav88dev
dav88dev

Reputation: 698

VueJS - v-bind:style + hover

I need to use CSS hover with VueJS v-bind:style directive but couldn't find information regarding it.

I need to bind styles for hover but v-bind:style.hover={} doesn't work. All the properties are going to be fetched from back-end, so I need to bind styles dynamically.

Are there other ways to bind styles on mouse over or CSS hover using VueJS?

Here is my code

This is the object :

button: {
    colorBackd: '#1e2021',
    colorBackdHover: '#000000',
    text: 'Results',
    color: '#d3e0ff',
    colorHover: "#ffffff",
    borderColor: '#d3e0ff',
    borderColorHover: "#ffffff"
},

Here is the html element that needs to be bound with styles

<button type="button"
    :style="{
    color:button.color,
        backgroundColor:button.colorBackd,
        borderColor:button.borderColor,
    }"
    class="btn btn-outline-info large-button">

        {{ button.text }}

</button>

Thanks

Upvotes: 36

Views: 46827

Answers (8)

Jesse Adamson
Jesse Adamson

Reputation: 560

I'm using vue3 with composition api and decided there's 2 good ways to do this. You can use a slot and variable like so:

<MenuItem v-slot="{ active }">
  <a href="#" :class="[active ? 'bg-neutral-600' : '', text-sm']">File</a>
</MenuItem>

Or you can use any template variables in the CSS section with v-bind() like so:

<template>
  <MenuItem class="menuClass">File</MenuItem>
</template>

<script>
export default {
  ...
  setup() {
    return {
      myObject,
    };
  },
};
</script>

<style>
.menuClass:hover {
  background-color: v-bind("myObject.hoverColor");
}
</style>

Upvotes: 3

Sweet Chilly Philly
Sweet Chilly Philly

Reputation: 3219

An extremely simple solution I found was to use the v-bind:class directive instead:

in my case i needed to add a hover when this element is inactive:

:class="{'inactive': !item.count}"

In this case, I am able to add an inactive property to my class, and then i can simply style that class with hover properties like so:

.inactive {
  color: black;

  &:hover {
    background-color: green;   
  }
}

Upvotes: 0

Afraz Ahmad
Afraz Ahmad

Reputation: 5386

I wanted to change z-index on hover so that hovered p tag appears at top. To do so I had to listen for event along with some value.

enter image description hereenter image description hereenter image description here

<template>
...
<p @mouseover="changeZIndex"
   @mouseleave="changeZIndexToOriginal({$event,old_z_index})
>
...
</template>


<script>
...methods
changeZIndex(e){
    //change to new z-index
    e.target.style.zIndex = 5 //to show on top
}
changeZIndexToOriginal(e){
    //e.$event is  an event which is trirgered. to get event along with some value we have to use this approach
    // e.old_z_index is z-index that I want to set back again. I am just using loop index to set z-index
    e.$event.target.style.zIndex = e.old_z_index
}
...
</script>

Using above approach we can change anything related to target element.

Upvotes: 0

estani
estani

Reputation: 26457

After seeing this is not implemented in vue I decided to use an overlay, which adds up to using :style to the overlay that will be shown by changing the opacity.

It is basically:

<div id="test" :style="style">
  <div class="overlay" :style="style.hover"></div>
</div>

var testArea = Vue.component('test-area', {
  template: '<div id="test" :style="style"><div class="overlay" :style="style.hover"></div></div>',
  computed: {
    style() {
      return {
        backgroundColor: '#0f0',
        hover: {
          backgroundColor: '#f00'
        }
      };
    },
  }
});

new Vue({
  el: '#app'
});
#test {
  position: relative;
  width: 100px;
  height: 100px;
}

#test>.overlay {
  opacity: 0;
}

#test:hover>.overlay {
  width: 100%;
  height: 100%;
  position: absolute;
  opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <test-area></test-area>
</div>

Upvotes: 0

Terry
Terry

Reputation: 66103

Improved solution: use CSS custom properties and variables

If you only intend to work with modern/evergreen browsers, then using CSS custom properties and variables is the way to go! You can actually pass CSS custom properties into the :style binding, e.g.

computed: {
  styleObject: function() {
    return {
      '--color': this.button.color,
      '--color-hover': this.button.colorHover
    }
  }
}

And in your template:

<custom-button :style="styleObject" />

For the CSS, it's just a matter of:

button {
  color: var(--color);
}

button:hover {
  color: var(--color-hover);
}

The advantage of this method is that you can scope CSS custom properties, so these variables will only apply to your specific button component when you define the CSS properties at the element level (instead of in :root).

The only drawback is that you have to iteratively declare all the variables in both hover and unhovered states, which can be a little bit cumbersome. However, I see this is a very minor disadvantage, compared to the benefits that you reap from using CSS variables.

See proof-of-concept below:

var customButton = Vue.component('custom-button', {
  template: '#custom-button',
  data() {
    return {
      button: {
        colorBackd: '#1e2021',
        colorBackdHover: '#000000',
        text: 'Results',
        color: '#d3e0ff',
        colorHover: "#ffffff",
        borderColor: '#d3e0ff',
        borderColorHover: "#ffffff"
      }
    };
  },
  computed: {
    styleObject() {
      return {
        '--button-color': this.button.color,
        '--button-background-color': this.button.colorBackd,
        '--button-border-color': this.button.borderColor,
        
        '--button-color--hover': this.button.colorHover,
        '--button-background-color--hover': this.button.colorBackdHover,
        '--button-border-color': this.button.borderColorHover
      };
    },
  },
});

new Vue({
  el: '#app'
});
button {
  color: var(--button-color);
  background-color: var(--button-background-color);
  border-color: var(--button-border-color);
}

button:hover {
  color: var(--button-color--hover);
  background-color: var(--button-background-color--hover);
  border-color: var(--button-border-color--hover);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<div id="app">
  <custom-button></custom-button>
</div>

<script type="text/template" id="custom-button">
  <button type="button" :style="styleObject" class="btn btn-outline-info large-button">
        {{ button.text }}
  </button>
</script>

Original sotluion: use JS-based mouse events

You can store the hovered state of the element in its data, say hoverState. It is set to false by default, and is toggled to true when @mouseenter is fired, and back to false when @mouseleave is triggered:

Then, you can simply bind a computed property to the style attribute, for example, styleObject. In this styleObject, you can return the correct CSS styles depending on the hoverState found in the component's data:

var customButton = Vue.component('custom-button', {
  template: '#custom-button',
  data() {
    return {
      button: {
        colorBackd: '#1e2021',
        colorBackdHover: '#000000',
        text: 'Results',
        color: '#d3e0ff',
        colorHover: "#ffffff",
        borderColor: '#d3e0ff',
        borderColorHover: "#ffffff"
      },
      hoverState: false
    };
  },
  computed: {
    styleObject() {
      var modifier = '';
      if (this.hoverState)
        modifier = 'Hover';
        
      return {
        color: this.button['color' + modifier],
        backgroundColor: this.button['colorBackd' + modifier],
        borderColor: this.button['borderColor' + modifier]
      };
    },
  },
  methods: {
    updateHoverState(isHover) {
      this.hoverState = isHover;
    }
  }
});

new Vue({
  el: '#app'
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<div id="app">
  <custom-button></custom-button>
</div>

<script type="text/template" id="custom-button">
  <button type="button" :style="styleObject" @mouseenter="updateHoverState(true)" @mouseleave="updateHoverState(false)" class="btn btn-outline-info large-button">
        {{ button.text }}
  </button>
</script>

Upvotes: 47

muka.gergely
muka.gergely

Reputation: 8329

If you use single file components, then you just need to make the button style scoped:

<template>
    <button></button>
</template>

<style scoped>
    button {
        /* your button style here */
    }
</style>

Or even for a more confined styling there are modules, shown here: How to correctly use "scoped" styles in VueJS single file components?

Upvotes: 0

dravog
dravog

Reputation: 21

You can assign your Vuejs Component an id and apply the required hover style in a stylesheet.

<button id="styledButton" type="button"
:style="{
color:button.color,
    backgroundColor:button.colorBackd,
    borderColor:button.borderColor,
}"
class="btn btn-outline-info large-button">

    {{ button.text }}
</button>

then in tag,

<style>
styledButton:hover {
color: #FFFFFF
};
</style>

If you want the hover style to contain any dynamic data. make a tag that calls a computed property.

<style>{{computedStyle}}</style>

Upvotes: 2

VitalickS
VitalickS

Reputation: 59

Other way (using css variables).

You need create HTML with style

<style>
     div[vueid=${_uid}] { --btn-hover: ${`Here your hover brush`} }
</style>

and inject it into your component.

<template>
   <div vueid="_uid">
      <button></button>
      <div v-html="styleCode"></div>
   </div>
</template>

Then simply use this variable in static css file to setup button style.

button:hover { background: var(--btn-hover); }

Note: you can describe default variable value in :root selector.

Upvotes: 5

Related Questions