88

In vue single file component. I import a svg file like this:

import A from 'a.svg'

And then how can I use A in my component?

3
  • 3
    what do you need it for? tons of information is lacking here Commented Jun 22, 2017 at 9:58
  • 1
    This question is not Vue specific, as it depends on the webpack loader you use to load your SVG files. What do you want to achieve with that import statement? Do you want A to be a String containing your SVG file? Do you want to inline or simply include a.svg in your template? Do you simply want to ensure that a.svg is available in when your component is inserted? Please extend your question with use case, the relevant parts of your Vue Component, and the relevant parts of your webpack configuration. Commented Jun 22, 2017 at 11:10
  • 1
    Not only is it not Vue specific, it's not Webpack specific... Commented Jul 27, 2018 at 2:48

16 Answers 16

57

Based on the information you provided, what you can do is:

  1. Install vue-svg-loader

npm install --save-dev vue-svg-loader

  1. Configure webpack:

module: {
    rules: [
      {
       test: /\.svg$/,
       loader: 'vue-svg-loader', // `vue-svg` for webpack 1.x
      },
    ],
  },

  1. Import the svg and use it as a regular component:

<template>
  <nav id="menu">
    <a href="...">
      <SomeIcon class="icon" />
      Some page
    </a>
  </nav>
</template>

<script>
import SomeIcon from './assets/some-icon.svg';

export default {
  name: 'menu',
  components: {
    SomeIcon,
  },
};
</script>

Reference: https://github.com/visualfanatic/vue-svg-loader

Sign up to request clarification or add additional context in comments.

3 Comments

This solution is really nice. However, it took me a while to figure out two things: 1. if you are using vue CLI 3.x, you need to create a vue.config.js file to modify the webpack config as described in github.com/visualfanatic/vue-svg-loader#vue-cli and 2. If you are using TypeScript, you also need to declare a svg module, as also described in the docs: github.com/visualfanatic/vue-svg-loader/blob/master/docs/…
Great tool - using it I however faced an Invalid Component Definition - but quickly found the reason in github.com/visualfanatic/vue-svg-loader/issues/1
Installing an npm package doesn't help understand how it works.
48

I've gotten the following to work in Vue 3. Doesn't require messing with webpack or installing any third party plugins.

<template>
  <img :src="mySVG" />
</template>

<script>
export default {
  name: 'App',
  data(){
    return {
      mySVG: require('./assets/my-svg-file.svg')
    }
  }
}
</script>

Note: I'm aware that you cannot modify certain pieces of the SVG when using it in img src, but if you simply want to use SVG files like you would any other image, this seems to be a quick and easy solution.

2 Comments

If you want to use an image just as is - then you even don't need to require it at all. Just do <img src="@/assets/my-svg-file.svg" />.
Not true, at least not in all cases. In Vue 3, vue-cli 4.5.2, npm run serve delivers SVGs with content-type "text/html" and the image does not show.
39

If you have control over the svg file, you can just wrap it in a vue file like so:

a.vue:

<template>
  <svg>...</svg>
</template>

Just require the file like this afterwards: import A from 'a.vue'

3 Comments

are there any downsides to this approach, besides having to wrap every SVG if you have a ton?
If you have a lot of svg files you should probably load them "properly" with a loader as @renato-krcelic suggests.
Also, if you have a lot of svg files, this will add significantly to your app's loading time, because instantiating vue components doesn't come for free. This is especially relevant in Vue 2, less so in Vue 3.
12

If you are using Webpack you can use the require context to load SVG files from a directory. Be aware that this will put all SVG files within your Javascript files and might bloat your code though.

As a simplified example I am using this svg component:

data() {
    return {
        svg: ''
    };
},

props: {
    name: {
        type: String,
        required: true
    }
}

created() {
    this.svg = require(`resources/assets/images/svg/${this.name}.svg`);
}

The template simply looks like this:

<template>
    <div :class="classes" v-html="svg"></div>
</template>

Normally you can't simply load SVG files like that and expect them to be used with a v-html directive since you are not getting the raw output. You have to use the Webpack raw-loader so make sure you get the raw output:

{
    test: /\.svg$/,
    use: [
        {
            loader: 'raw-loader',
            query: {
                name: 'images/svg/[name].[ext]'
            }
        },
        {
            loader: 'svgo-loader',
            options: svgoConfig
        }
    ]
}

The example above also uses the svgo-loader since you will want to heavily optimize your SVG files if you do down this route.

Hopefully this help you or anyone else out on how to solve this without diving straight into a third-party solution to fix this.

Comments

9

You can also use something like this:

<template>
  <img :src="logo"></img>
</template>

<script>
import logo from '../assets/img/logo.svg'

export default {
  data() {
    return {
      logo
    }
  }
}
</script>

This doesn't require installing external modules and works out of the box.

2 Comments

Note you can not affect the properties of a svg ( fill / stroke ) if you use it as an image src. stackoverflow.com/questions/44695560/…
True, but some people just need this. I just needed this.
8

I would just use vue-svg

Install via Vue CLI 3:

vue add svg

Input:

<img src="@/assets/logo.svg?data" />

Output:

<img src="data:image/svg+xml;base64,..." />

or this is work also...

import LogoImage from "@/assets/logo.svg?inline"

Comments

5

For anyone using Vite and not Webpack: Solution 2 from this article worked great for me with Vue 3 inside Astro.

  1. Install vite-svg-loader.
  2. Add to Vite config:
import svgLoader from 'vite-svg-loader';

export default defineConfig({
  plugins: [
    // ...
    svgLoader(),
  ],

});

or for Astro:

import { defineConfig } from 'astro/config';

import vue from '@astrojs/vue';
import svgLoader from 'vite-svg-loader';

// https://astro.build/config
export default defineConfig({
  integrations: [
    vue(),
  ],
  vite: {
    plugins: [vue(), svgLoader()],
  },
});
  1. Define component for convenience:
<script setup>
import { defineAsyncComponent } from 'vue';

const props = defineProps({
  name: {
    type: String,
    required: true,
  },
});

const icon = defineAsyncComponent(() => import(`./icons/${props.name}.svg`));
</script>

<template>
  <component :is="icon" />
</template>
  1. Use:
<template>
  <Icon name="foobar" />
</template>

<script>
import Icon from './Icon.vue';

export default {
  components: {
    Icon,
  },
}
</script>

1 Comment

I knew if I scrolled far enough I would find a Vue 3 & Vite answer. Thank you!
3

I like to use pug as a template engine (comes with many advantages) - if you do so, you will be able to easily include files like SVG's just by writing:

include ../assets/some-icon.svg

That's it! there is nothing else to do - I think this is an very easy and convenient way to include stuff like smaller svg's - file's easily included code is still clean!

Here you can get some more information how to include PugJS into you Vue instance https://www.npmjs.com/package/vue-cli-plugin-pug

2 Comments

Where would you put that include? I'm confused because it looks like something that would be part of the javascript... but if that's the case you haven't shown the pug markup?
Just have a look at the PugJS documentation, there it is documented how to do it: pugjs.org/language/includes.html
3

If you're using Vite (which most of you should), then you can append ?raw at the end of your import.

import arrowLeftIcon from '@/assets/svg/arrow-left.svg?raw'

This will return the raw svg string and you can render it as an html using v-html:

<div v-html="arrowLeftIcon" class="w-4 h-4" />

1 Comment

Just a note: The code sample presumes the "Composition API". If using the "Options API" in Vue, it is not possible to use the arrowLeftIcon import directly as a v-html value. It has to be made available as a data item (just list arrowLeftIcon with the shorthand syntax in the returned data object), a computed property or a function return value.
2

First you need a specific loader for the component which will contain the svg my webpack.base.config.js

module: {
    rules: [
      {
        test: /\.svg$/,
        loader: 'vue-svg-loader',
      },
      {
        test: /\.vue$/,

        use: [
                    {
            loader: "vue-loader", 
            options: vueLoaderConfig
                    },
                    {
                        loader: "vue-svg-inline-loader",
                        options: { /* ... */ }
                    }
                ]
      }
//.. your other rules
}

docs of vues-svg-inline-loader : https://www.npmjs.com/package/vue-svg-inline-loader
docs of vue-svg-loader : https://www.npmjs.com/package/vue-svg-loader

Next, you can initialise a vue file

<template>
<div>

  <img svg-inline class="icon" src='../pathtoyourfile/yoursvgfile.svg' alt="example" />

</div>
</template>

<script>
import axios from 'axios'



export default {
  name: 'logo',
  data () {
  },
  }

</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
#logo{
  width:20%;
}
.rounded-card{
    border-radius:15px;
}
//the style of your svg 
//look for it in your svg file ..
//example
.cls-1,.cls-7{isolation:isolate;}.cls-2{fill:url(#linear-gradient);}.cls-3{fill:url(#linear-gradient-2);};stroke-width:2px;}..cls-6{opacity:0.75;mix-blend-mode:multiply;}.cls-7{opacity:0.13;}.cls-8{fill:#ed6a29;}.cls-9{fill:#e2522b;}.cls-10{fill:#ed956e;}.cls-185{fill:#ffc933;}..cls-13{fill:#ffd56e;}.cls-14{fill:#1db4d8;}.cls-15{fill:#0f9fb7;}.cls-16{fill:#3ad4ed;}.cls-17{fill:#25bdde;}.cls-18{fill:#fff;}
//


</style>


Your svg fils must dont contain style tag so copy paste the style in the vue style with scoped propoerty to keep it specific to this component
you can just load you component in specific place of your app and use it

<template>

<v-app id="app">

    <logo/>
   <router-view/>

</v-app>



</template>

<script>
import logo from './components/logo.vue'

export default {
  name: 'App',
  data(){
    return {
      //your data
    }
  },
  components:{
logo //the name of the component you imported
  },


  }
}
</script>

<style>
#app {

  font-family: 'Hellow', sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #070b0f;
  margin-top: 60px;
}

</style>

Comments

0

You can always save it as a .svg file in your /static/svg/myfile.svg (using webpack) and just use it as an image file: <img src="/static/svg/myfile.svg">. No require / import / loader needed.

1 Comment

doesn't work if you want to interact with the SVG with css classes or fill:currentColor
0

+1 for @Stephan-v's solution, but here's a slightly modified approach for 2021 with Webpack 5.

  1. Your Vue component <template/>

Option A: Single SVG file

<template>
  <svg viewBox="0 0 24 24">
    <use :xlink:href="require('@/assets/icons/icon.svg')"></use>
  </svg>
</template>

Option B: SVG Sprite (e.g. for FeatherIcons)

<template>
  <svg viewBox="0 0 24 24">
    <use
      :xlink:href="require('@/assets/icons/sprite.svg') + `#${iconName}`"
    ></use>
  </svg>
</template>

<script>
export default {
  props: {
    // Dynamic property to easily switch out the SVG which will be used
    iconName: {
      type: String,
      default: "star",
    },
  },
};
</script>
  1. You may need a Webpack loader.

NOTE: You may not need the Webpack Loader if you're using Vue 3 (as mentioned above) or Vite. If you're using Storybook or Nuxt, you will likely still need it.

$ npm install svgo-loader -D
$ yarn add svgo-loader -D

webpack.config.js (or similar)

module.exports = {
  mode: "development",
  entry: "./foo.js",
  output: {},
  // ... other config ...
  module: {
    rules: [
      /////////////
      {
        // Webpack 5 SVG loader
        // https://webpack.js.org/guides/asset-modules/
        // https://dev.to/smelukov/webpack-5-asset-modules-2o3h
        test: /\.svg$/,
        type: "asset",
        use: "svgo-loader",
      },
    ],
    /////////////
  },
};
  1. Done!

1 Comment

I'm using vite, what is the syntax for this:
0

I was able to get svgs loading inline via

<div v-html="svgStringHere"></div>

Where svgStringHere is a computed property that returns an svg as a string

Comments

0

SVG as a component

My favourite approach is to create an SVG Vue component and then use it wherever I need it.

The good thing about this is that you can add encapsulated custom styles, pass props or have custom logic (e.g. animation, badges, etc) to fit your needs.

Example

<template>
   <svg
     class="custom"
     width="314"
     height="318"
     viewBox="0 0 252 213"
     fill="none"
     xmlns="http://www.w3.org/2000/svg"
        <path id="somePath" ... />
   </svg>
</template>
<style scoped>
  .custom {
     -webkit-transform: translate(-30px, -20px);
     transform: translate(-30px, -20px);
  }
</style>

Import it anywhere in the Vue app

<script setup lang="ts">
import MySvg from "@/components/MySvg.vue"
</script> 
<template>
  <div>
    <MySvg />
  </div>
</template>

2 Comments

Not sure why the downvote; this is a valid technique. Maybe not for a simple static SVG, but definitely for re-usable SVG's for variety of contexts.
@Kalnode neither do I, thanks for your vote and msg.
0

If you want to have full control over the SVG (e.g. styling with CSS or adding interactivity), you can import it inline using Vue and Webpack like this:

<template>
  <component :is="dynamicLogo" class="logo" />
</template>

<script>
export default {
  name: "LogoComp",
  computed: {
    dynamicLogo() {
      return () =>
        import(
          /* webpackChunkName: "logo" */ "@/assets/logo-default.svg?inline"
        );
    },
  },
};
</script>

<style scoped>
.logo { width: 151px; }
</style>

Obs:

  • The ?inline query assumes you're using vue-svg-loader or a similar loader that supports inline SVGs.
  • You may need to configure your Webpack to handle SVGs with that loader.
  • This technique is useful when you want to style or animate the SVG directly, as it becomes part of the DOM.

Comments

0

Based on answer from Badal Saibo, I was unhappy with the result, since it includes an extra div. So here it comes, with pure Vite + Vue3:


<template>
 <SVGLogo />
</template>

<script setup lang="ts">
import { createStaticVNode, defineAsyncComponent } from 'vue'

const SVGLogo = defineAsyncComponent(() => import('./path/to/your.svg?raw').then(content => {
  return createStaticVNode(content.default, 1)
}))
</script>

The template will only include your SVG, and nothing else.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.