Vue.js can't toggle a font-awesome icon

I ran into this issue recently when using Vue.js 2.5.x with FontAwesome 5.5.x — the icon classes were not being updated as expected.

After switching from the FontAwesome Web Fonts + CSS implementation to SVG + JS, the following code no longer worked:

<i :class="[sortByFirstNameAsc ? 'fa-chevron-up' : 'fa-chevron-down', 'fa']"></i>

What would happen is that FontAwesome JavaScript would fire and wrap the <i> tag and replace it with an SVG element, as in the following simplified example:

<span data-v-2614dbd6="">
  <svg data-v-2614dbd6="" class="svg-inline--fa fa-caret-up" ...">
    ...
  </svg>

  <!-- <i data-v-2614dbd6="" class="fa fa-caret-up"></i> -->
</span>

Unfortunately, the active class was being toggled on the inner, hidden <i> tag and not the outer, visible SVG element.

The workaround that restored the dynamic active class toggling was to wrap the FontAwesome icons in a span and use the v-show directive, as illustrated in the following code snippet:

<span v-show="sortByFirstNameAsc"><i class="fa fa-caret-up"></i></span>
<span v-show="sortByFirstNameDesc"><i class="fa fa-caret-down"></i></span>

The FontAwesome documentation now recommends using their Vue component to avoid conflicts in the DOM:

Compatibility Heads Up! If you are using Vue you need the vue-fontawesome package or Web Fonts with CSS.

The SVG core package is helpful and recommended in the following cases:

  • to subset a large number of icons into only the icons that you are using
  • as base libraries for larger integrations with tools like React, Angular, Vue, or Ember (in fact our own components use these packages)
  • as CommonJS/ES6 Modules bundling tool like Webpack, Rollup, or Parcel
  • as UMD-style loader library like RequireJS
  • directly on the server with CommonJS (see our Server Side Rendering docs

"i" tag comments out after fire turning to svg, use some wrap <span v-if="marked"><i class="far fa-check-square"></i></span>


The Font Awesome library you used doesn't know about Vue. It takes the <i> that you wrote and turns it into an <svg>, and at that point, it's been stolen from Vue. Vue no longer controls it. The answer that Dialog gave was a good one: wrap it with a <span>. But then you pointed out another scenario it doesn't work for.

To solve your scenario where wrapping with a <span> still doesn't work, use key="fa-sort-up". This will force Vue to re-render the wrapper, at which point Font Awesome will update the icon. Here's the updated jsFiddle for your example:

<span key="fa-sort-up" v-if="sort && descending"><i class="fas fa-sort-up"></i></span>
<span key="fa-sort-down" v-else-if="sort"><i class="fas fa-sort-down"></i></span>
<span key="fa-sort" v-else><i class="fas fa-sort"></i></span>

You can use anything you want for the key, as long as it's unique.