Frontend Development 9 min read

Implement SVG Hover Color Change with a Vue Custom Directive

This article explains how to simplify SVG hover color changes in Vue by creating a reusable custom directive that dynamically modifies the fill attribute or swaps SVG markup, reducing duplicated markup and improving maintainability for both simple and complex SVG graphics.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Implement SVG Hover Color Change with a Vue Custom Directive

In front‑end development, a common requirement is to change the style of an SVG image on hover. The naïve approach is to embed two separate SVGs and toggle their visibility with v-show , which quickly becomes cumbersome.

For simple SVGs whose appearance can be controlled solely by the fill attribute, you can change the color directly without duplicating the markup. The article demonstrates a more elegant solution by creating a Vue custom directive that handles the hover effect.

<template>
  <div>
    <button @click="toggleColor">切换svg颜色</button>
    
    <svg v-show="isRed" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
      <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red"/>
    </svg>
    
    <svg v-show="!isRed" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
      <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="blue"/>
    </svg>
  </div>
</template>

<script>
export default {
  data() {
    return { isRed: true };
  },
  methods: {
    toggleColor() {
      this.isRed = !this.isRed;
    }
  }
};
</script>

To avoid this verbosity, the article introduces a custom directive named v-color . By applying the directive to the parent element of the SVG, the directive’s lifecycle hooks can access the SVG DOM node and modify its fill on mouseenter/mouseleave.

// directives/color.js
const color = {
  // other hooks omitted for brevity
  beforeMount(el, binding) {
    const svg = el.querySelector('svg');
    const original = svg.style.fill;
    el.onmouseenter = () => { svg.style.fill = binding.value; };
    el.onmouseleave = () => { svg.style.fill = original; };
  }
};

export default {
  install(app) {
    app.directive('color', color);
  }
};

Registration in main.js :

import { createApp } from 'vue';
import App from './App.vue';
import color from './directives/color';

const app = createApp(App);
app.directive('color', color);
app.mount('#app');

Usage in a component:

<template>
  <div v-color="'blue'">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
      <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red"/>
    </svg>
  </div>
</template>

For complex SVGs where multiple attributes need to change, the directive can accept an array containing two SVG strings (normal and hover states) and replace the parent element’s innerHTML on hover.

// directives/color.js (complex case)
const color = {
  beforeMount(el, binding) {
    const [normalSvg, hoverSvg] = binding.value;
    el.onmouseenter = () => { el.innerHTML = hoverSvg; };
    el.onmouseleave = () => { el.innerHTML = normalSvg; };
  }
};

Importing SVGs as raw strings (e.g., using Vite’s ?raw query) enables this approach.

In summary, the article provides a reusable Vue directive that simplifies SVG hover effects by either adjusting the fill attribute for simple graphics or swapping entire SVG markup for more complex cases, improving code maintainability and reducing duplication.

frontendJavaScriptVueSVGCustom Directivehover effect
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.