Vuetify: [Feature Request] Component for Flexible SVG icons

Created on 19 Jun 2018  路  14Comments  路  Source: vuetifyjs/vuetify

Problem to solve

Work without font

Don't need include icon fonts and additional css files for this icons ( svg icons betters that font icons. My opinion based on this article https://css-tricks.com/icon-fonts-vs-svg/
From Article:

If you can go IE 9+ / Android 3+, inline SVG is better at pretty much everything than icon fonts".

Full Vuetify box

Will create default folder icons in Vuetify. All icons, which vuetify use, will be include in the box. Like (icon-selection-control, arrow_drop_down, chevron_left, chevron_right and others.....) .

When user include Vuetify in own project, he does not need include additional files.

Faster works

All icons will bundle with your script. It is faster loading in browser than bundle.js + file.fonts + file.css.

Additionally, every project don't use all icons from the font. You can include only needed icons, it makes less size for your project.

More combinations

You can use some icons from FontAwesome and some icons from Material Design Icons https://materialdesignicons.com .

You can create own unlimited combinations for your project. Maybe it's more work for including, but it's more flexible.

VIcon is one component which make Vuetify depended from additional files like fonts and .css and my propose can help to solve this inconvenience and make Vuetify more flexible

Proposed solution

I propose integrate https://github.com/Justineo/vue-awesome

Not All project, Only one component
https://github.com/Justineo/vue-awesome/blob/master/src/components/Icon.vue

OR

to use this idea for new v-icon compoent, wich can use both type (font icon component or svg icon component )

Compact Store

Store your icons in object. If you look on the https://materialdesignicons.com All icons you can download as svg or view svg in Inline SVG for HTML. Example for icon "menu-down" https://materialdesignicons.com/icon/menu-down:

Inline SVG for HTML

<svg style="width:24px;height:24px" viewBox="0 0 24 24">
<path fill="#000000" d="M7,10L12,15L17,10H7Z" />
</svg>

For Examle, We save our icon as object in common store :

file vuetify/icons/arrow-drop-down

 import  VIcon from 'vuetify/components/VIcon'
 VIcon.register({
  'arrow-drop-down': {
    d: 'M7,10L12,15L17,10H7Z'
 })

Sizes saved as default

 Vue.use(Vuetify, { icons: {width:24, height:24, type:'svg'} })

Flexible & Asynchronous component

You can connect special icon directly in component. For Example:

If You using asynchronous component with as Webpack Chunk, your icons will registered when component will be loaded. And special icons store in loaded component.

/*
   chunk
*/ 
import  'vuetify/icons/special-icon-1';
import  'vuetify/icons/special-icon-2';
import  'vuetify/icons/special-icon-3';
import  'vuetify/icons/special-icon-4';
import  'vuetify/icons/special-icon-5';


 export default {
 name: 'special-component'
 ...
}

In addition, to use of the component can be the same

<v-icon>name-icon<v-icon>

By default we start functional for svg icons, which registered in the box. And user can register own icons.

If user wants fonts add options

Vue.use(Vuetify, 
{ icons: 
  {type:'fa' // fa or mdi  if use fonts
 } })

On this website https://materialdesignicons.com to gather collection icons directly for Vuetify.

What do you think about this idea??
P.S. Sorry for my English, I am in the process of studying ;)

feature

Most helpful comment

I'd like to mention an additional benefit. Icon fonts can be large and heavy, specially material design icons. They include a wide choice of icons but most projects will just use a reduced subset.

Subsetting a webfont based on used css classes is hard. It's easier to use tree shaking with webpack 4, which works out of the box. This is the approach used for @mdi/js, which only loads SVG path data for icons that are used.

All 14 comments

I think this is very good idea that will be very helpful for people that want to have full control over all assets that are used on their website and want to optimize the amount of loaded assets, and don't load any unused icons in large icon-font bundle.
@johnleider do you have any plan for future releases when you will include this kind of feature into Vuetify ?

I'd like to support it within v-icon but I haven't had time to learn how to do it. Would love to chat with anyone who is an expert.

I cannot call my self an expert, but I have some experience with SVG icons and how to work with them, so we can chat about it. Just say where and when, and I will try manage it for my self, to be able to chat with you.

@struers-mfr come msg me in the community, https://community.vuetifyjs.com

I was wondering about using multiple icon sets. The material design ones provide some good icons that seem lacking from like font-awesome. It seems that currently there's no way to accomplish this very easily and it sounds like this suggestion would help provide that capability.

I would imagine supporting more than one icon set would be a lot easier to do than this though. Not sure if it's worth opening up a separate issue for that.

You can use md, mdi and fa together, you just need to include/imoprt all of them

I'd like to mention an additional benefit. Icon fonts can be large and heavy, specially material design icons. They include a wide choice of icons but most projects will just use a reduced subset.

Subsetting a webfont based on used css classes is hard. It's easier to use tree shaking with webpack 4, which works out of the box. This is the approach used for @mdi/js, which only loads SVG path data for icons that are used.

At MDI we are recommending our users migrate away from the webfont due to the growing file size. Adding support for @mdi/js to this project would definitely be recommended going forward. We can then add an example of integrating with this project to the work-in-progress documentation for Vue on our new site.

@JamesCoyle I'll take a look

Another additional benefit is the behaviour with VIcon inside elements.
I am using custom individually imported font-awesome icons throughout my project this way:

<template>
  <div>
    <font-awesome-icon :icon="faCircle"></font-awesome-icon>
  </div>
</template>

<script>
  import { faCircle } from '@fortawesome/pro-solid-svg-icons';

  export default {
    data() {
      faCircle,
    },
  };
</script>

The VCheckbox uses internally a hardcoded VIcon in order to show its state.
As I didn't include the full font-awesome icons using the css webfonts, I am not able to use this component and currently there's no way I can workaround this.

If VIcon and elements that accept an icon argument could also parse imported SVG objects as the font-awesome-icon element does, it would be, _awesome_. 馃槅

@vinerz you can override the internal icons either at startup or dynamically by specifying individual icons by their logical internal names:

Vue.use(Vuetify, {
  iconfont: "fa",
  icons: {
    "checked": "bug_report",
    "unchecked": "mdi-anchor"
  }
})

This sets the full icon set to font-awesome but overrides just the checkbox icons.
After this point, you can also dynamically change them:

this.$vuetify.icons.checked = 'fas fa-check-square'  // or any other source
this.$vuetify.icons.unchecked = 'far fa-square'   // or any other source

Now, the JS-based SVG icons are a bit different because they aren't run again on a checkbox change (I use a v-switch to avoid that where I need to avoid web fonts), but I just wanted to clarify in the non-JS case that VCheckbox doesn't actually hard-code the icons. You could use the checked box from font-awesome but the unchecked box from MDI, if you wanted. Or a Vuetify icon for checked and a bug icon for unchecked. And with one (two) assignments, you could make that affect all future checkboxes in the instance. All of the icons in all of the controls reference the name indirectly via the vue instance's $vuetify.icons assignments, which you can override and/or change dynamically.

I don't think this will help you use the JS-based SVGs though in the checkbox case. It will work for expanding accordion triangles because the alternative form just rotates the icon 180 degrees (it doesn't use two icons). And I think it will work for everything else, it is only checkboxes that use two different icons. The workaround I've used is to use v-switch for now for that one case. Maybe some of the others here will have some other ideas.

Hey @appurist, thanks for the answer!

I am aware about changing the icons at startup!
It would be lovely to use this approach, but as you are also doing, I am using JS SVGs and VSwitch as workaround, hahaha 馃槃

I was mentioning that the VIcon element itself is hardcoded, so I can't, for example, replace the icon element as a slot. Making it accept JS SVGs would be the best thing ever for us!

@vinerz It probably doesn't accept an icon since one icon is not enough, but I supposed it could technically add two props to define those. A checkbox is a special case. That said, you can replace both icons with the methods above, so specifying them as props isn't really an improvement. But that's not the real problem...

As I understand it, it does accept SVGs now, in the sense that you can specify them by name. But it won't work with the JS-based SVG icons since it doesn't know to rerun the JS code on an icon change, so you don't see that it has changed. If you could refresh the element, it would show it. Perhaps rather than adding two icon props, there could be a prop specifically for the JS SVG case, to tell the VCheckbox code that it needs to take extra steps to show the new icon on an checkbox value change: e.g. force-refresh or update-refresh or just refresh props. I don't know enough about the SVG JS font implementation to know what those steps might be though. Perhaps removing the element and adding it again is one way. That would need to be done internally within the VCheckbox implementation though.

This is now supported as of alpha.11 with paths.

Was this page helpful?
0 / 5 - 0 ratings