Font Awesome in React, Vue and Angular

Use the official component packages with the icon library pattern, keep tree-shaking intact, and work around the v7 removal of the dynamic icon component.

React

npm install @fortawesome/react-fontawesome
npm install @fortawesome/fontawesome-svg-core
npm install @fortawesome/free-solid-svg-icons
npm install @fortawesome/free-regular-svg-icons
npm install @fortawesome/free-brands-svg-icons
# Pro projects add the matching pro packages instead
// The library pattern: add icons once at the application root, then refer to
// them by name anywhere. Short names are what make this convenient.
import { library } from '@fortawesome/fontawesome-svg-core';
import { faCartShopping, faBell, faUser } from '@fortawesome/free-solid-svg-icons';

library.add(faCartShopping, faBell, faUser);

// ---- Later, in any component -------------------------------------------
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';

export function Toolbar() {
  return (
    <header>
      {/* By name, using the library */}
      <FontAwesomeIcon icon="bell" />

      {/* Or by importing the definition directly: the tree-shakeable path */}
      <FontAwesomeIcon icon={faCartShopping} />

      {/* Sizing, colour and animation are props, not classes */}
      <FontAwesomeIcon icon="user" size="lg" color="#6d28d9" spin />

      {/* An icon that is the only content of a button needs a label */}
      <button type="button" aria-label="Notifications">
        <FontAwesomeIcon icon="bell" aria-hidden="true" />
      </button>
    </header>
  );
}
// v7 removed the dynamic "object" icon component that resolved icons by
// string from the whole library (and the dynamic importing feature that
// went with it). The supported patterns now are:

// 1. By string, for icons registered with library.add()
<FontAwesomeIcon icon="bell" />
<FontAwesomeIcon icon={['fas', 'bell']} />      // explicit prefix
<FontAwesomeIcon icon={['far', 'bell']} />

// 2. By imported definition: nothing to register, fully tree-shakeable
import { faBell } from '@fortawesome/free-solid-svg-icons';
<FontAwesomeIcon icon={faBell} />

// 3. A custom icon defined in your own project
import { faMyGlyph } from './icons/faMyGlyph';
<FontAwesomeIcon icon={faMyGlyph} />

// What no longer works: passing a string that was never registered, or
// relying on the component to look up an arbitrary icon at runtime.
PropValuesNote
iconA string, a tuple, or a definitionThe only required prop
sizexs through 2xlMaps to the sizing scale
fixedWidthBooleanEqual widths for a vertical list
spin / pulseBooleanBuilt-in animation
beat / fade / bounce / shakeBooleanv7 animation props
rotation / flip90, 180, 270 / horizontal, verticalPower transforms
transformA string such as shrink-2The SVG transform syntax
maskAn icon definitionComposites on top of the icon
listItemBooleanFor fa-li style lists
swapOpacityBooleanDuotone layer swap
aria-hidden / titleBoolean / stringAccessibility, exactly as in plain markup
💡
Adding icons to the library at the root keeps components short but weakens tree-shaking: the icons reachable from the library object are all retained. Importing each icon definition where it is used and passing the definition is the pattern that lets a bundler drop the icons you never reference.

Vue 3

// main.js — the same library pattern
import { createApp } from 'vue';
import { library } from '@fortawesome/fontawesome-svg-core';
import { faBell, faCartShopping } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import App from './App.vue';

library.add(faBell, faCartShopping);

createApp(App)
  .component('FontAwesomeIcon', FontAwesomeIcon)   // global registration
  .mount('#app');
<script setup>
// Local import instead of a global component: better for tree-shaking.
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { faBell } from '@fortawesome/free-solid-svg-icons';

const props = defineProps({ unread: { type: Number, default: 0 } });
</script>

<template>
  <button type="button" :aria-label="`Notifications, ${props.unread} unread`">
    <FontAwesomeIcon :icon="faBell" />
    <span v-if="props.unread" class="badge">{{ props.unread }}</span>
  </button>
</template>

<!-- Props are identical to React's: size, spin, rotation, transform, mask,
     listItem, swapOpacity. Attribute names stay kebab-case in templates. -->
// A global component that wraps the size and colour so templates stay clean.
import { h } from 'vue';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';

export const AppIcon = {
  props: { icon: { type: [String, Array, Object], required: true }, size: { type: String, default: '1x' } },
  setup(props) {
    return () => h(FontAwesomeIcon, {
      icon: props.icon,
      size: props.size,
      class: 'app-icon',
      'aria-hidden': true
    });
  }
};

// Used as <AppIcon icon="bell" /> with the styling in one stylesheet.

Angular

npm install @fortawesome/angular-fontawesome @fortawesome/fontawesome-svg-core
npm install @fortawesome/free-solid-svg-icons
// app.config.ts — register the icons your application uses.
import { ApplicationConfig } from '@angular/core';
import { FaIconLibrary } from '@fortawesome/angular-fontawesome';
import { faBell, faCartShopping } from '@fortawesome/free-solid-svg-icons';
import { faGithub } from '@fortawesome/free-brands-svg-icons';

export const appConfig: ApplicationConfig = {
  providers: [
    {
      provide: FaIconLibrary,
      useFactory: () => {
        const library = new FaIconLibrary();
        // register icons by prefix, or add whole icon packs
        library.addIcons(faBell, faCartShopping, faGithub);
        return library;
      }
    }
  ]
};
import { Component, input } from '@angular/core';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { faBell } from '@fortawesome/free-solid-svg-icons';

@Component({
  selector: 'app-notification-button',
  imports: [FaIconComponent],
  template: `
    <button type="button" [attr.aria-label]="label()">
      <fa-icon [icon]="bell" [animation]="'beat-fade'" />
      @if (unread() > 0) { <span class="badge">{{ unread() }}</span> }
    </button>
  `
})
export class NotificationButtonComponent {
  // Import the definition and pass it in: fully tree-shakeable.
  readonly bell = faBell;
  readonly unread = input(0);
  readonly label = input('Notifications');
}

// Inputs on fa-icon mirror the other frameworks:
// [icon] [size] [fixedWidth] [rotate] [flip] [spin] [pulse] [border]
// [transform] [mask] [inverse] [listItem] [pull] [animation] [stackItemSize]
FrameworkPackageRegister whereTree-shaking
React@fortawesome/react-fontawesomelibrary.add at the root, or pass a definitionBest with direct definitions
Vue 3@fortawesome/vue-fontawesomeGlobal component plus library.addBest with local imports
Angular@fortawesome/angular-fontawesomeFaIconLibrary providerBest with direct definitions
Svelte@fortawesome/svelte-fontawesomeImport and passGood
AstroAny of the above in the framework islandPer islandDepends on the island
Plain HTMLdom.watch()The library plus a watcherPoor
// Custom icons in a typed setup: the definition is a plain object.
import { IconDefinition } from '@fortawesome/fontawesome-svg-core';

export const faTelescope: IconDefinition = {
  prefix: 'fas',
  iconName: 'telescope',
  icon: [512, 512, [], 'f8ff', 'M... long path data ...'],
  //    ^width ^height ^ligatures ^unicode ^path
};

// Register it like any other icon:
// library.add(faTelescope);
// or pass it directly: <FontAwesomeIcon :icon="faTelescope" />

// TypeScript note: the tuple is [width, height, ligatures, unicode, path] for
// a single-path icon, or an array of path strings for a multi-path icon.

FAQ

Why is my bundle growing with every icon?
The library pattern registers icons at the root, so every icon reachable from the library object is retained. Import each icon definition at the point of use and pass the definition to the component instead of a string.
What replaced the v6 dynamic icon component?
Nothing equivalent. v7 removed the ability to resolve an arbitrary icon name at runtime, because that requires bundling every icon. Register what you use with the library, or import definitions directly — both are static and bundle-friendly.

SVG with JavaScript: how it works and when to use it Build-time optimisation, subsets and bundle budgets

Last refreshed 2026-09-18.