Is it wrong to create a vue component for every svg icon? - vue.js

I like to use inline svg in my projects because it gives me great control over things like width, height, fill color, stroke width and stroke color using css and js(props). I usually create a vue.js SFC (single file component) for every SVG icon. Here's an example:
<!-- IconsArrowRight.vue -->
<template>
<svg
viewBox="0 0 14 14"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.57026 0.888947L5.98842 2.46006L9.4199 5.89117L0.333374 5.89117L0.333374 8.10895H9.4199L5.98842 11.5401L7.57026 13.1112L13.6681 7.00006L7.57026 0.888947Z"
/>
</svg>
</template>
And then I would use it like this (I'm using tailwindCSS for styling):
<template>
<div>
<IconsArrowRight class="w-8 h-8 text-blue-500" />
</div>
</template>
I use more than 50 icons in my project, and I've created a vue.js component for each one; Is it a bad practice regarding production performance to have so many components just for icons? Should I use font-icons instead, or any other alternative method?

Using one .vue file for one .svg is totally fine IMO. It will not have any big impact performance-wise, just maybe take a bit longer when building your app but nothing that critical IMO.
Also, using it this way can have quite some flexibility in some rare situations regarding HTML specification.
Now, regarding the best approach ever, I'd probably say to use #unocss/preset-icons or any package based on Iconify simply because it will bring you all the available and imaginable icons on the fly, with no drawbacks and a LOT of flexibility + nice DX.
Here is an article in 4 parts that will explain all the reasoning behind this approach and how it can be integrated universally to any solution (even if not using Antfu's solution).

Most probably either using the svg as component or as font icon from performance side I would not consider any issue at all. Vue.js is a framework that can be used for large scale applications and your components are not heavy at all, they just use an SVG.
My personal preference would be to be used as font icons as you mentioned and use a component that you will be passing as props the font icon, so with this way you would have 1 component for all svgs.
About the styling, again using a prop to pass all the styles and bind that prop with the :class
This would be much cleaner I think,
Cheers

Related

Vuetify v-card not inside v-col despite being placed there

Okay, so I am trying to setup a simple grid layout with three v-cards at equal distances.
<v-main>
<v-container>
<v-row>
<v-col>
<v-card outlined tile>Card 1</v-card>
</v-col>
<v-col>
<v-card outlined tile>Card 2</v-card>
</v-col>
<v-col>
<v-card outlined tile>Card 3</v-card>
</v-col>
</v-row>
</v-container>
</v-main>
Now, according to the docs and examples they have this should leave me with 3 cards at equal distances, and it does indeed.
Problem is that moment I hover over any of them, they all darken. Looking through the dev tools reveals following issue:
As you can see, the v-cards are not inside v-cols as they should be. Yet, I can't see any errors in the code. Am I missing some extra rule or something?
I believe the problem with darkening on hover should be elsewhere and is not related to the oddity that you see in the Vue debugger. I don't think there is something wrong with your code (compare it to what I mention in #1 below). I tend to believe that the oddity in the debugger is either its own bug or a bug (or feature?) related to how the debugger reflects the Vuetify internals, which doesn't spoil the real app behavior. Here are my arguments:
Look at Vuetify grid with cards example - it is structured the same way as your example (ignore their 'cols' attribute of v-col tag - they showcase an uneven spread of columns, and if you remove that attribute you get pretty much your own example with 3 cards, each inside of its own v-col). However, if you try to copy-paste this standard Vuetify example into an empty Vue CLI app and look into the debugger you see the same odd hierarchy. Check my screenshot: This, however, doesn't spoil the DOM model, where the v-cards are inside of v-cols as expected: This also doesn't create any problems with the actual app behavior. Changing background color at hover (I added that simple CSS change to Vuetify original example just to try to reproduce your original problem) works like a charm. Note that red background in one card of the screenshot - it spreads to the single hovered card only.
I remember seeing the same Vuetify hierarchy oddity in Vue debugger in the past, though it didn't create any problems and didn't seem to be caused by any bugs in the code. I just ignored it at that time.
I also copied your example into a codepen adding just two basic things: the CSS to test hovering (the same as I added in #1 above) and the basic Vue object creation and mounting (which I'd suppose you should have auto-generated).
The CSS:
.v-card:hover {
background-color: red;
}
The JS:
new Vue({
vuetify: new Vuetify(),
}).$mount('#app')
The hovering also works well in that codepen (if I understand correctly the kind of problem you mentioned). I should mention there is one difference in CSS to what I had to use in #1, though. In #1 a custom CSS class (<v-card class="imgCard">) was used as v-cards are inside of another high-level v-card there, so I couldn't use '.v-card' to highlight just one nested card there - they would all highlight together otherwise. BTW, isn't that the problem you experience by chance?
So overall, I think that either your original code has something else that causes the problem (presuming you might have simplified it when writing the question), or I didn't get what kind of hovering you mean. Anyways, I'm quite certain that the oddity in Vuetify debugger doesn't mean there is something wrong with the code itself.

Is there a simple way to change the chevron icons in a nested Nav component?

I personally and a lot of customers think the default icons for links with nested items in the Nav component are strange. Hence I want their look and behavior to change from this:
to this:
(In the screenshots the size is also different, but that's just from the context's I took them. I just want to change the icons).
The latter is btw also used by Microsoft OWA (Outlook Online), which also uses Fluent UI React. The only thing that I could come up with (but which doesn't work really well) was to hide the default chevron using styles and modifying the rendered link onRenderLink to display the other chevrons.
I'm aware of this question, but changing the icons via style is no option and I guess no longer a preferred way by fluent ui.
Is there any better or official way I'm missing?
I've taken a look at the code and unfortunately the icon is baked into the Nav component. Your best option would be to style the icon similar to what is being done in this codepen.

Does Vue support svg elements?

I want to generate svg compoenents which uses svg tags. Does Vue supports that?
Note, that svg elements needs to be created in the corretc namespace and vue might not be able to handle that out of the box
Yes, you can use Vue to create dynamic SVGs. There even is an example in the docs. In this podcast, Sarah Drasner talks about the combination of Vue, SVG and https://greensock.com/.
I have used this approach to build https://fn.hofmann-vratny.de/configurator, which simply binds SVG elements/properties to reactive Vue data. This worked really well for me.
You can create a component and add the SVG tags inside like:
<template> SVG Content Here </template>
Note: You might find some issues with certain SVG tags.
There's also some libraries you can use like svg-to-vue-component
Hope this helps.

When to use styled component vs when to use css prop in emotion?

Is there a best practice or list of pros and cons in deciding when to use a styled component instead of the css prop?
I generally prefer styledComponent but, there are certain edge cases like styling your <Link /> for react-router where you have to provide a compiled style to className prop.
There is no harm in using CSS props but, there is a chance of accidentally overriding your styles, plus it makes your JSX messier. But if you know what you are doing and you are heavily using composition then IMO it is quite a powerful feature.
It is much easier to understand and manage the styled-components, like when using themes you can encapsulate the whole styling logic away from your JSX. +1 to styled-components for lego based design.
I think it is safe to say, you can use styled-components and CSS together but adopting either one for the majority of your components.
I absolutely love how you can override your base components using emotion's composition(which saves us from passing weird props and helps to keep the props cleaner) but at the same time you should not abuse it as from personal experience it's tempting to just use CSS composition where you should be using props like isBold fontSize: "sm" ...

Can I include scoped css without Vue Loader?

For a project where Vue is dropped in, is using style or similar available to components?
Vue.component('vue-sup', {
template: '<div>Sup</div>',
style: '* { color: blue; }'
})
I tried adding the styles inside the template like:
<div>
<style>
.here{}
</style>
<div>Sup</div>
</div>
which didn't work because the template parser detected a tag with side effects
Vue's implementation of scoped css is entirely a feature of vue-loader, and thus only works with compilation. Scoped css momentarily made a debut into Html 5 but saw almost no adoption and was dropped entirely as far as I know. There is the anticipation that "Shadow DOM" may be supported broadly and could be use to add scoped css, but adoption is not there yet either.
So at this point you can add unique classes or ids obviously to a parent container and scope your css that way, but is understandably not what you are asking for nor is it always practical.
The best alternative is a pollyfill. There are several that are available. Here is one by Sam Thorogood and another by Thomas Park but if you do a quick search you will likely discover more.
I came across the same problem and I'm able to insert styling inside Vue template
by creating a component that will dynamically insert a <style> tag on the DOM. This might be impractical like #skribe said but it allows me to have separate CSS from JS without using .vue extension.
You can take a look at this