Upgrading from Font Awesome 5 and 6 to 7
The breaking changes that matter, the class and family renames to search for, and a migration order that keeps the icons visible throughout.
The breaking changes
| Area | Font Awesome 6 | Font Awesome 7 | Action |
|---|---|---|---|
| Fixed width | Opt-in with fa-fw | On by default | Remove fa-fw; check any layout depending on variable widths |
| Decorative icons | Announced | Hidden from screen readers by default | Remove aria-hidden="true"; add a label where the icon carries meaning |
sr-only | Available | Removed | Use visually-hidden or a <span class="fa-sr-only"> pattern |
| Sass build | LibSass and Dart Sass | Dart Sass only | Migrate the build tooling first |
| CSS custom properties | Limited | Used throughout | Replace hard-coded overrides with --fa-* properties |
| Font family names | Font Awesome 6 Free | Font Awesome 7 Free | Update any hand-written @font-face or font-family |
| Brands | Font Awesome 6 Brands | Font Awesome 7 Brands | Same |
| Dynamic icon lookup (JS) | Supported | Removed | Register icons with the library, or import definitions |
fa-sharp naming | Font Awesome 6 Sharp | Font Awesome 7 Sharp | Same |
| Icon renames | Some v5 names aliased | Aliases removed | Update to the current canonical names |
fa-v4compatibility | Available | Removed | Fix the class names instead |
| Integration packages | Contrib ecosystem | Some dropped | Move to the official packages |
⚠️
The decorative-icons change is the one that silently alters behaviour. In v6 a bare icon with no label was announced by its ligature or code point, which sounded like gibberish but at least indicated something was there. In v7 it is hidden by default, so a button whose only content is an icon becomes an unnamed button — a real accessibility regression unless you add a label.
Finding what needs changing
# 1. Version and family names in your own CSS
grep -rn "Font Awesome 5\|Font Awesome 6" src/ --include="*.css" --include="*.scss"
# 2. A hand-written @font-face block: it needs the new family name and files
grep -rn "@font-face" src/ -A 5 | grep -i "awesome"
# 3. The classes that changed behaviour or vanished
grep -rno "fa-fw\|fa-sr-only\|fa-v4compatibility" src/
# 4. Bare icons with no adjacent text, which v7 will hide
grep -rnE "<i class=\"[^\"]*fa-[a-z-]+[^\"]*\"></i>" src/ | head -50
# 5. Hand-written aria-hidden on icons, now redundant or harmful
grep -rn "aria-hidden" src/ | grep -i "fa-"
# 6. Deprecated icon names that were aliased in v6
grep -rn "fa-arrow-alt\|fa-sign-in-alt\|fa-trash-alt\|fa-comment-alt" src/// A script that reports every icon class in a directory and flags the ones
// that need attention, so the migration is a list rather than a scavenger hunt.
import { readdir, readFile } from 'node:fs/promises';
import { join } from 'node:path';
const FLAGGED = /\b(fa-fw|fa-sr-only|fa-v4compatibility|fa-arrow-alt-|fa-trash-alt|fa-sign-in-alt|fa-comment-alt)\b/g;
const ICON = /\bfa-[a-z0-9-]+\b/g;
async function scan(dir) {
const found = new Map();
async function walk(current) {
for (const entry of await readdir(current, { withFileTypes: true })) {
const path = join(current, entry.name);
if (entry.isDirectory()) { await walk(path); continue; }
if (!/\.(html|jsx|tsx|vue|svelte|ts|js|mdx)$/.test(entry.name)) continue;
const source = await readFile(path, 'utf8');
for (const match of source.match(FLAGGED) ?? []) {
if (!found.has(match)) found.set(match, []);
found.get(match).push(path);
}
for (const match of source.match(ICON) ?? []) {
if (!found.has(match)) found.set(match, []);
if (found.get(match).length < 3) found.get(match).push(path);
}
}
}
await walk(dir);
return found;
}
const report = await scan('src');
for (const [name, files] of [...report].sort()) {
console.log(name.padEnd(28), files.slice(0, 3).join(', '));
}- Search the compiled CSS too, if any of it is checked in. A stale
../webfonts/fa-solid-900.woff2reference from v6 is a 404 that shows as boxes. - Check the fixture files and the tests as well. An icon asserted by class name in a test will pass while the page renders nothing.
- Grep for the Sass mixins you use, not just the classes: the Dart Sass-only change breaks a LibSass build before any icon appears.
A migration order that keeps working
- Copy the v7 files or update the package, and update the font-family names in any hand-written CSS. Run the build and confirm the icons still render — both versions use the same class names for the majority of the set.
- Load the v7 stylesheet alongside the v6 one only if you cannot switch at once. Duplicate
@font-facerules with different family names coexist harmlessly; the same family name with two different files does not. - Remove
fa-fwand verify the alignment of any column that relied on it. The default width is now the icon's natural width, which is usually what the design wants. - Add accessible names to every icon-only control before removing the old
aria-hiddenattributes. This is the change most likely to cause a regression, so do it deliberately rather than as a search and replace. - Rename deprecated icon names to their canonical v7 equivalents, guided by the report script.
- Update the framework component packages to their v7 releases and re-check tree-shaking, since the dynamic lookup removal changes how icons resolve.
- Remove any
fa-v4compatibilityorsr-onlyusage, then delete the v6 stylesheet and the old font files. - Re-run a visual check on every page: the icon metrics changed slightly, so a badge that sat perfectly may now be one pixel off.
<!-- Before: v6, icon announced by its code point -->
<button type="button" class="icon-btn"><i class="fa-solid fa-bell"></i></button>
<!-- After: v7, decorative and hidden, with the name on the control -->
<button type="button" class="icon-btn" aria-label="Notifications">
<i class="fa-solid fa-bell"></i>
</button>
<!-- A meaningful icon next to text: hidden, and the text carries the meaning -->
<button type="button" class="btn">
<i class="fa-solid fa-trash" aria-hidden="true"></i> Delete project
</button>
<!-- A standalone icon that must be announced: give it a real accessible name -->
<span class="status">
<i class="fa-solid fa-circle-check" role="img" aria-label="Healthy"></i>
API
</span>| Icon role | Markup | Why |
|---|---|---|
| Decorative, next to text | aria-hidden="true" on the icon | The text already names the action |
| The only content of a control | Nothing on the icon; aria-label on the control | The control is what receives focus |
| Meaningful inline in prose | role="img" plus aria-label | Otherwise it is invisible and its meaning is lost |
| A status indicator | role="img" and a label, or text beside it | Colour and shape alone are not enough |
| A decorative flourish | aria-hidden="true" | Nothing to announce |
The migration is mostly mechanical except for the accessibility change, which is a genuine improvement that requires a decision per icon. Budget for it: it is the part that reviewers and auditors will look at, and the part that a v6 codebase is least likely to have documented.
FAQ
Is there a compatibility stylesheet for v6 classes?
No. The
fa-v4compatibility stylesheet that bridged v4 to v5 was removed, and v7 does not ship a shim. The class names that changed are few, so a search-and-replace plus the report script above is faster than maintaining a shim.Why are my icons invisible after upgrading, with no console error?
The most likely cause in v7 is that the icon is now hidden from assistive tech and you were relying on the old announcement for a visible width or layout. Check the font-family names in your CSS first, then check whether an icon-only control lost its accessible name.
Related
Installing Font Awesome Accessibility and performance trade-offs
Last refreshed 2026-09-18.