Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic icon components #5

Closed
wheatjs opened this issue Jan 11, 2021 · 15 comments
Closed

Dynamic icon components #5

wheatjs opened this issue Jan 11, 2021 · 15 comments

Comments

@wheatjs
Copy link

wheatjs commented Jan 11, 2021

Is it possible to dynamically use icons?

I'm using the vitesse template and would previously use something like <Icon :icon="myIconVariable" /> but now it seems like that no longer exists so I was wondering if it is still possible to do something like that.

I tried something like this without much luck

<template>
  <component :is="myIconVariable.replace(':', '-')" />
</template>

<script setup>
const myIconVariable = 'mdi:vuejs'
</script>
@antfu
Copy link
Member

antfu commented Jan 12, 2021

No, this plugin is designed to be used statically. Can you combine it with vite-plugin-purge-icons to have both SSR icons and runtime dynamic icons.

@wheatjs
Copy link
Author

wheatjs commented Jan 12, 2021

Oh okay, gotcha. I'll give that a shot, thanks!

@ngekoding
Copy link

Oh okay, gotcha. I'll give that a shot, thanks!

Have you make it work with vite-plugin-purge-icons?

@IanVS IanVS mentioned this issue Sep 16, 2021
@antfu antfu changed the title dynamic icon components Dynamic icon components Jan 5, 2022
@antfu antfu pinned this issue Jan 5, 2022
@antfu
Copy link
Member

antfu commented Jan 5, 2022

Due to the mechanism of how unplugin-vue-components works, there is no way to infer a component from a dynamic string. (unplugin-icons only resolved icons at build time)

The workarounds for this is:

<IconA v-if="cond1"/> 
<IconB v-else-if="cond2"/>
<IconC v-else-if="cond3"/>
<IconD v-else />

Or

<script setup>
import MdiAlarm from '~icons/mdi/alarm'
import MdiAccount from '~icons/mdi/account'

const items = [
{
  name: 'Alarm',
  icon: MdiAlarm,
},
{
  name: 'Account',
  icon: MdiAccount,
}
]
</script>

<template>
  <div v-for="i of items">
    <component :is="i.icon"/>
  </div>
</template>

@husayt
Copy link

husayt commented Jan 19, 2022

Along with autoImport one can achieve even more elegant solution. Use the same IconResolver you used in unplugin components:

  AutoImport({
      imports: ["vue"],
      resolvers: [
        IconsResolver({
          componentPrefix: "icon",
          enabledCollections: ["carbon", "mdi"],
        }),
      ],
      dts: "src/auto-imports.d.ts",
    }),

Then you don't need to even import and the above will look like this:

<script setup>
const items = [
{
  name: 'Alarm',
  icon: IconMdiAlarm,
},
{
  name: 'Account',
  icon: IconMdiAccount,
}
]
</script>

<template>
  <div v-for="i of items">
    <component :is="i.icon"/>
  </div>
</template>

@zhangchenna
Copy link

AutoImport

你这么写没用吧

@r-priyam
Copy link

Alternatively this component method can also be used to get the icons dynamically rendered using string. Is it advisable to use it? @antfu

@mvksims
Copy link

mvksims commented Feb 28, 2022

@husayt it works!

@leosin
Copy link

leosin commented Mar 1, 2022

Along with autoImport one can achieve even more elegant solution. Use the same IconResolver you used in unplugin components:

  AutoImport({
      imports: ["vue"],
      resolvers: [
        IconsResolver({
          componentPrefix: "icon",
          enabledCollections: ["carbon", "mdi"],
        }),
      ],
      dts: "src/auto-imports.d.ts",
    }),

Then you don't need to even import and the above will look like this:

<script setup>
const items = [
{
  name: 'Alarm',
  icon: IconMdiAlarm,
},
{
  name: 'Account',
  icon: IconMdiAccount,
}
]
</script>

<template>
  <div v-for="i of items">
    <component :is="i.icon"/>
  </div>
</template>

Uncaught (in promise) ReferenceError: IconMdiAlarm is not defined

@blooddrunk
Copy link

Just found that defineAsyncComponent also won't work. Had to use @iconify/vue and @iconify/utils to render icons dynamically. Hope there would be a way eventually.

@overtrue
Copy link

@lrstanley
Copy link

[...]
Uncaught (in promise) ReferenceError: IconMdiAlarm is not defined

Doing this on multiple sites at the moment without issues. May want to make sure you have explicitly enabled the collection via enabledCollections. Can't recall if the auto-import as non-component requires that or not, but I do have that in my config, and no issues.

@transtone
Copy link

unocss Icons preset is welcome.

@JACKZGGG
Copy link

我项目中涉及到大量icon,如果每一个icon都要一个vue文件,再导入那就太恶心了

@JACKZGGG
Copy link

与 autoImport 一起可以实现更优雅的解决方案。使用与拔出组件相同的 IconResolver:

  AutoImport({
      imports: ["vue"],
      resolvers: [
        IconsResolver({
          componentPrefix: "icon",
          enabledCollections: ["carbon", "mdi"],
        }),
      ],
      dts: "src/auto-imports.d.ts",
    }),

然后你甚至不需要导入,上面的内容将如下所示:

<script setup>
const items = [
{
  name: 'Alarm',
  icon: IconMdiAlarm,
},
{
  name: 'Account',
  icon: IconMdiAccount,
}
]
</script>

<template>
  <div v-for="i of items">
    <component :is="i.icon"/>
  </div>
</template>

谢谢,按照你的方法至少我不用再创建一个个vue文件了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests