Install Dependencies

Vue 3 projects need vue-fontawesome v3. Core SVG engine is same as React but the Vue component package is independently maintained. FontAwesome's Vue component renders icons as inline SVG elements, deeply integrated with Vue's reactivity system and virtual DOM for efficient icon updates and animation control.

npm (Vue 3)
npm install @fortawesome/vue-fontawesome@latest @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons
Extra Style Packages
# Regular style (outline icons) npm install @fortawesome/free-regular-svg-icons # Brand Icons npm install @fortawesome/free-brands-svg-icons
Version Note:Vue 3 projects must use @fortawesome/vue-fontawesome@3 or later. Vue 2 projects use @fortawesome/vue-fontawesome@2. The two versions have significant API differences.

Component Registration

FontAwesome Vue components support global and local registration. After global registration, use <font-awesome-icon> directly in any template, suitable for medium-to-large projects with frequent icon usage. Local registration only takes effect within specific component scope, suitable for projects with few icons or strict bundle size requirements. In practice, choose registration strategy flexibly based on project scale, or combine both approaches.

Global Registration

Register globally in main.js/main.ts, suitable for medium to large projects.

import { createApp } from 'vue' import App from './App.vue' import { library } from '@fortawesome/fontawesome-svg-core' import { faHome, faUser, faGear } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' library.add(faHome, faUser, faGear) createApp(App) .component('font-awesome-icon', FontAwesomeIcon) .mount('#app')

Local Registration

Register locally in single components, suitable for small projects or specific pages.

<script setup> import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { faStar } from '@fortawesome/free-solid-svg-icons/faStar' </script> <template> <div> <font-awesome-icon :icon="faStar" /> </div> </template>

Basic Usage

The <font-awesome-icon> component core props are similar to React, supporting icon, size, spin, pulse, beat and other common props. Unlike directly using CSS class names, the component approach integrates better with Vue's data binding and conditional rendering, enabling flexible dynamic icon display.

<!-- Basic icon --> <font-awesome-icon icon="fa-solid fa-home" /> <!-- Set size --> <font-awesome-icon icon="fa-solid fa-star" size="2x" /> <!-- Spin animation --> <font-awesome-icon icon="fa-solid fa-spinner" spin /> <!-- Pulse animation --> <font-awesome-icon icon="fa-solid fa-circle-notch" pulse /> <!-- Custom style --> <font-awesome-icon icon="fa-solid fa-heart" beat style="color: red;" class="my-icon" />

The string format "fa-solid fa-home" requires the icon to be registered via library.add(). You can also pass the imported icon object directly.

Composition API Usage

Using Composition API in <script setup> gives more flexible icon import management with tree-shaking optimization. Composition API is Vue 3's recommended development pattern, organizing component logic into composable functions that lower coupling between icon management and business logic. Through library.add() combined with single icon imports, each component's icon dependencies are clearly visible for easier maintenance and refactoring.

<script setup> import { ref } from 'vue' import { library } from '@fortawesome/fontawesome-svg-core' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { faSun, faMoon, faCheck, faXmark } from '@fortawesome/free-solid-svg-icons' // Add to library for string reference library.add(faSun, faMoon, faCheck, faXmark) const isDark = ref(false) function toggleTheme() { isDark.value = !isDark.value } </script> <template> <button @click="toggleTheme" class="btn btn-outline-secondary"> <font-awesome-icon :icon="isDark ? 'fa-solid fa-moon' : 'fa-solid fa-sun'" class="me-1" /> {{ isDark ? 'Dark Mode' : 'Light Mode' }} </button> </template>

Add to library for string reference

On-demand Import

For optimal bundle size, import from single icon paths to ensure webpack/vite tree-shaking works. Tree-shaking is a core optimization in modern build tools, identifying and removing unreferenced code through static analysis of import statements. FontAwesome's icon library contains tens of thousands of icons; importing all would add megabytes to your bundle. Through single icon path imports, build tools can precisely retain only the icons actually used, which is especially important for large enterprise projects.

// Best practice: import single icon, supports tree-shaking import { faHome } from '@fortawesome/free-solid-svg-icons/faHome' import { faUser } from '@fortawesome/free-solid-svg-icons/faUser' import { faBell } from '@fortawesome/free-solid-svg-icons/faBell' import { library } from '@fortawesome/fontawesome-svg-core' library.add(faHome, faUser, faBell) // Avoid full import (significantly increases bundle size) // import { faHome, faUser, faBell } from '@fortawesome/free-solid-svg-icons' // Avoid FontAwesome JS auto-replace (dom.watch), it has compatibility issues with Vue's virtual DOM // It has compatibility issues with Vue’s virtual DOM mechanism

Single icon path format: @fortawesome/free-solid-svg-icons/faXxx, PascalCase file naming. Both Vite and Webpack 5 correctly identify and tree-shake these imports.

Vue 2 vs Vue 3 Differences

Comparison ItemVue 3Vue 2
Package Version@fortawesome/vue-fontawesome@3@fortawesome/vue-fontawesome@2
Component Tag<font-awesome-icon><font-awesome-icon>(Same)
Composition APIVue 3 <script setup>Vue 2 @vue/composition-api
Icon Binding:icon="faHome" or icon="fa-solid fa-home"(Same)
Same as Vue 3Full TypeScript typesNo native TS support
SSR Type SupportNative support (Nuxt 3)Extra config needed (Nuxt 2)
Animation Propsspin, pulse, beat, fadespin, pulse, beat, fade all supportedBasic spin animation support

Migration advice: New projects always use Vue 3 + vue-fontawesome@3; existing Vue 2 projects stay on v2, do not mix versions.

Common Scenarios

Button Icons

Embed icons in buttons with loading state for better user feedback.

<script setup> import { ref } from 'vue' import { library } from '@fortawesome/fontawesome-svg-core' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { faSpinner, faDownload, faCheck } from '@fortawesome/free-solid-svg-icons' library.add(faSpinner, faDownload, faCheck) const loading = ref(false) async function handleDownload() { loading.value = true await new Promise(r => setTimeout(r, 2000)) loading.value = false } </script> <template> <button @click="handleDownload" :disabled="loading" class="btn btn-primary" > <font-awesome-icon :icon="loading ? 'fa-solid fa-spinner' : 'fa-solid fa-download'" :spin="loading" class="me-1" /> {{ loading ? 'Downloading...' : 'Start Download' }} </button> </template>

List Icons

Add icons before list items to improve readability and visual hierarchy.

<script setup> import { library } from '@fortawesome/fontawesome-svg-core' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { faCircleCheck, faCircleXmark, faCircleExclamation } from '@fortawesome/free-solid-svg-icons' library.add(faCircleCheck, faCircleXmark, faCircleExclamation) const items = [ { text: 'Database connected', status: 'success' }, { text: 'Config validation passed', status: 'success' }, { text: 'Cache warmed', status: 'warning' }, { text: 'Email service not configured', status: 'error' }, ] const statusMap = { success: { icon: 'fa-solid fa-circle-check', color: '#20c997' }, warning: { icon: 'fa-solid fa-circle-exclamation', color: '#f59f00' }, error: { icon: 'fa-solid fa-circle-xmark', color: '#e03131' }, } </script> <template> <ul class="list-unstyled"> <li v-for="item in items" :key="item.text" class="mb-2"> <font-awesome-icon :icon="statusMap[item.status].icon" :style="{ color: statusMap[item.status].color }" fixed-width class="me-2" /> {{ item.text }} </li> </ul> </template>

Conditional Rendering

Switching icons based on component state is a simple and effective feedback pattern.

<script setup> import { ref } from 'vue' import { library } from '@fortawesome/fontawesome-svg-core' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons' library.add(faEye, faEyeSlash) const visible = ref(false) const password = ref('') </script> <template> <div class="input-group"> <input :type="visible ? 'text' : 'password'" v-model="password" class="form-control" placeholder="Enter password" /> <button class="btn btn-outline-secondary" @click="visible = !visible"> <font-awesome-icon :icon="visible ? 'fa-solid fa-eye' : 'fa-solid fa-eye-slash'" /> </button> </div> </template>

Nuxt 3 Integration

In Nuxt 3, create a plugin file to register FontAwesome components globally, avoiding duplicate imports. Nuxt 3's plugin system auto-loads during app initialization, making registered components available app-wide. For SSR projects, this ensures consistent server and client rendering, avoiding layout shifts from client hydration.

// plugins/fontawesome.js import { library } from '@fortawesome/fontawesome-svg-core' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { faHome, faUser, faGear } from '@fortawesome/free-solid-svg-icons' import { faGithub, faTwitter } from '@fortawesome/free-brands-svg-icons' library.add(faHome, faUser, faGear, faGithub, faTwitter) export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.component('font-awesome-icon', FontAwesomeIcon) })
<!-- Use directly in any page after registration --> <template> <div> <font-awesome-icon icon="fa-solid fa-home" size="2x" /> <font-awesome-icon :icon="['fab', 'github']" size="2x" /> </div> </template>

Use directly in any page after registration

Share

Related