-
Notifications
You must be signed in to change notification settings - Fork 624
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
How to handle dynamic icons or icon names? #267
Comments
You cannot load icons dynamically with the However, you can use nuxt-icon module to achieve this. |
I played around and made a few adjustments so that i can pass the <UIcon :name="getIcon(myDynamicIconName)" /> <template>
<span :class="getName" :style="getStyle" />
</template>
<script>
import { computed, defineComponent } from "vue";
import { classNames } from "../../utils";
export default defineComponent({
props: {
name: {
type: [String, Object],
required: true
},
class: {
type: String,
default: null
}
},
setup(props) {
const getName = computed(() => {
if(typeof props.name === 'string') {
return classNames(
props.name,
props.class
);
}
return props.class;
});
const getStyle = computed(() => {
if(typeof props.name === 'object') {
const data = {...props.name};
const svgUrl = `url("data:image/svg+xml,${encodeURIComponent(
`<svg xmlns='http://www.w3.org/2000/svg' viewBox='${data.left} ${data.top} ${data.width} ${data.height}' width='${data.width}' height='${data.height}'>${data.body}</svg>`
)}")`;
return {
'--svg': svgUrl,
'background-color': 'currentColor',
'-webkit-mask-image': `var(--svg), ${svgUrl}`,
'mask-image': 'var(--svg)',
'-webkit-mask-repeat': 'no-repeat',
'mask-repeat': 'no-repeat',
'-webkit-mask-size': '100% 100%',
'mask-size': '100% 100%',
};
}
return null;
});
return {
getName,
getStyle
};
}
});
</script> My own getIcon component using |
That's pretty much what the |
Ah ok, i didn't know that yet. I got it from the <UIcon :name="getIcon(myDynamicIconName)" /> // composables/getIcon.js
import { iconExists, getIcon, loadIcon } from '@iconify/vue';
import { computed, ref } from 'vue';
const icons = ref({});
const loader = async (icon) => {
if (!iconExists(icon)) {
await loadIcon(icon)
.then((data) => {
icons.value[icon] = data;
});
} else if (!icons.value[icon]) {
icons.value[icon] = getIcon(icon);
}
return icons.value[icon];
}
export default (icon) => {
const iconLoader = loader(icon);
return icons.value[icon];
} This is more practical in my app than defining all the icons first. Whereby some of them stem from user input and i would have to load all the icons. |
@9uenther Can this issue be closed? |
I don't think this should be closed - it's a very common use case, for example, we asynchronously fetch menu items that are stored in the CMS, and we have no idea what icons are going to be used by the editors. Ideally, the icon component should accept a string, and resolve the icon at runtime. |
As mentioned previously, for this case you should use https://github.com/nuxt-modules/icon. There is also no issue using both, for example on Volta we use |
Thanks for a swift reply Ben! What is the reason for not using Nuxt Icon by default if you don't mind me asking? |
Historically However, since this ui library was originally made for Volta and when this package by egoist was released https://github.com/egoist/tailwindcss-icons I made the choice to switch to a system with bundled icons like UnoCSS does: https://unocss.dev/presets/icons. It's a tiny bit more work as you have to install the iconify packages for the collections you want to use but this makes icons instantly load as they are bundled in your css instead of fetching them from the Iconify API when rendering the page the first time. |
In general, the component is fine. However, i would extend it by dynamic use, as i have already indicated above. I think Iconify also pretty perfect, because i can add my own icons with relatively little effort or make them available via api. |
As another work around, I created a dummy component that renders the icons that are "dynamic". This dummy component is not used anywhere but allows the icons to be included. :)
|
@Jak3b0 You can also put those in comments anywhere in your app, they will be picked up by Tailwind. |
Hi @benjamincanac , thanks for your response! Not sure I understand the relation with Tailwind in this case though. I had the icon names defined in an array of objects inside a computed property and the icons were not included. |
@benjamincanac No offense intended here but this is a very bad design decision.
So the problem we're trying to solve here is that "nuxt-icon causes icons to not instantly load", right? And I would agree that it's a pretty bad problem. The iconify API is not the most reliable, and occasionally icons don't render on the Nuxt UI official website. This is caused by a known issue in nuxt-icon, nuxt/icon#34 or nuxt/icon#99 Basically, nuxt-icon doesn't load the icon on the server side, and instead opt to call the iconify API from the client at all times. So the reasonable solution to the problem of "nuxt-icon icons doesn't instantly load" would be "fix nuxt-icon so that icons can be injected and bundled at build time". Instead of doing that, here we introduced another dependency so that icons can be injected by tailwind as a CSS icon. What's the problem with that?
What I'm trying to say here is that by introducing |
@benjamincanac how could i use dynamic or currently DropdownItem could that be extended to also allow |
@Sazzels This is unfortunately not possible at the moment, the |
I want to pass the names dynamically. But if they have not been loaded before, the icon does not appear.
Is it possible to use an
IconifyIcon
object like this?Docs: https://iconify.design/docs/icon-components/vue/get-icon.html
The text was updated successfully, but these errors were encountered: