How to include inline .svg in Nuxt application
Asked Answered
A

4

9

I want to do a common thing - include dynamically an svg HTML in Vue Nuxt application which I will able to style. To do this, I created a component but instead of image, I get a text data:image/svg+xhtml....

How to make it work?

<template>
   <div v-html="src"></div>
</template>
<script>
export default {
    name: 'Icon',
    props: {
        name: {
            type: String,
            required: true
        }
    },
    computed: {
        src() {
            const src = require(`assets/icons/${this.name}.svg`)
            return src
        }
    }
}
</script>
Affinal answered 3/2, 2020 at 17:3 Comment(0)
H
11

It seems like @nuxtjs/svg will do what you're trying to do. After installing it, try:

<template>
   <div v-html="src"></div>
</template>
<script>
export default {
    name: 'Icon',
    props: {
        name: {
            type: String,
            required: true
        }
    },
    computed: {
        src() {
            const src = require(`assets/icons/${this.name}.svg?raw`)
            return src
        }
    }
}
</script>
Hooknose answered 3/2, 2020 at 17:54 Comment(7)
Nice. I was trying to do it in a straight Vue project. That Nuxt plugin is a much better solution.Epaminondas
@Hooknose I have now text /_nuxt/5476b1293b10e0056bf8a8f9cf8c93c4.svg instead of imageAffinal
I had the same issue and replaced the <div v-html="src"></div> with <component v-bind:is="src"></component>. Also the src computed property can return this return require(`assets/icons/${this.name}.svg?inline`).defaultRejuvenate
upvoted what if all your svg files are inside node_modules folderYarbrough
@Yarbrough why would you put SVG files in the node_modules folder?Hooknose
@Hooknose not me but I library I am trying to use has its svg icons inside node_modules after installing it and i was wondering how to use itYarbrough
requiring inside the computed func drops a compiler error ! Module not found: Error: Can't resolve '~assets/img in component ...Triode
V
1

try doing this, watch out for the "/_nuxt/assets" extension.

       <td v-if="actions" class="px-4 flex flex-row py-2 justify-end">
          <span v-for="action in actions" :key="action.key">
            <NuxtLink :to="action.to + '/' + item['actions']">
              <a>
                <img class="pl-2 pr-2" 
       :src="`/_nuxt/assets/images/dataTableIcons/${action.value}.svg`"
                  :alt="action.value">
              </a>
            </NuxtLink>
          </span>
        </td>
Vivica answered 18/4, 2023 at 15:18 Comment(0)
C
0

Load the svg as text and parse into DOM

<script lang="ts" setup>
import { onMounted } from 'vue'

const props = defineProps<{ url: string }>()
const svgString = ref('')

onMounted(() => {
  fetch(props.url)
    .then(response => response.text())
    .then((svg) => {
      const parser = new DOMParser()
      const doc = parser.parseFromString(svg, 'image/svg+xml')
      const svgElement = doc.documentElement
      const svgContainer = document.createElement('div')
      svgContainer.appendChild(svgElement)
      svgString.value = svgContainer.innerHTML
    })
  })
</script>
<template>
  <div v-html="svgString" />
</template>
Cryptonymous answered 24/9 at 19:37 Comment(0)
E
-2

It's not easy and I tried a bunch of different solutions that "seemed" like they should work.

My understanding is that it comes down to how Webpack deals with "image" assets and using them inline vs stand-alone sort of changes the definition.

I've got a library of SVG icons that needed code access (eg change colors after run time) so I had to have the SVG inline. Here's where I landed, It's not ideal but it works.


Create a new component with a prop slot for SVG name. Inside that component add all your svg's as code. Wrap each in a v-if.

<template>
   <div class="svgIcon">
      <svg v-if="icon == 'name1'">...</svg>
      <svg v-if="icon == 'name2'">...</svg>
      <svg v-if="icon == 'name3'">...</svg>
      <svg v-if="icon == 'name4'">...</svg>
   </div>
</template>
<script>
  export default {
    props: ['icon']
  }
</script>

Then use the component by filling the name you want in the slot

<template>
   <div>
      <svgIcons :icon="name1"></svgIcons>
   </div>
</template>
<script>
  import svgIcons from '../path/to/iconsComponent.vue'
  export default {
    components: { svgIcons },
    ...
  }
</script>
Epaminondas answered 3/2, 2020 at 17:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.