From 9f5dc2c0df0cdba1113697bdd71637a404444065 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Tue, 6 Nov 2018 01:40:11 +0900
Subject: [PATCH] [WIP] Use FontAwesome Component for Vue (#3127)

* wip

* Rename

* Clean up

* Clean up

* wip

* wip

* Enable tree shaking

* :v:

* :v:

* wip

* wip

* Clean up
---
 gulpfile.ts                                   |  4 +-
 package.json                                  | 10 +-
 src/client/app/admin/views/announcements.vue  |  4 +-
 src/client/app/admin/views/ap-log.vue         |  8 +-
 src/client/app/admin/views/charts.vue         |  2 +-
 src/client/app/admin/views/cpu-memory.vue     |  4 +-
 src/client/app/admin/views/dashboard.vue      | 24 ++---
 src/client/app/admin/views/emoji.vue          |  8 +-
 src/client/app/admin/views/index.vue          | 24 ++---
 src/client/app/app.styl                       |  2 +-
 .../common/views/components/api-settings.vue  |  8 +-
 .../connect-failed.troubleshooter.vue         | 28 +++---
 .../views/components/connect-failed.vue       |  2 +-
 .../views/components/drive-settings.vue       |  2 +-
 .../app/common/views/components/error.vue     |  2 +-
 .../views/components/file-type-icon.vue       |  2 +-
 .../components/games/reversi/reversi.game.vue | 10 +-
 .../components/games/reversi/reversi.room.vue |  6 +-
 .../app/common/views/components/google.vue    |  2 +-
 .../common/views/components/media-banner.vue  |  4 +-
 .../app/common/views/components/menu.vue      |  7 +-
 .../views/components/messaging-room.form.vue  |  6 +-
 .../components/messaging-room.message.vue     |  4 +-
 .../views/components/messaging-room.vue       | 18 ++--
 .../app/common/views/components/messaging.vue |  8 +-
 .../views/components/mute-and-block.vue       |  2 +-
 .../app/common/views/components/nav.vue       |  2 +-
 .../common/views/components/note-header.vue   | 12 +--
 .../app/common/views/components/note-menu.vue | 16 +--
 .../common/views/components/poll-editor.vue   |  8 +-
 .../app/common/views/components/poll.vue      |  4 +-
 .../views/components/profile-editor.vue       | 10 +-
 .../app/common/views/components/signin.vue    |  2 +-
 .../app/common/views/components/signup.vue    | 30 +++---
 .../views/components/stream-indicator.vue     |  8 +-
 .../app/common/views/components/tag-cloud.vue |  6 +-
 .../app/common/views/components/theme.vue     | 18 ++--
 .../app/common/views/components/trends.vue    |  6 +-
 .../app/common/views/components/ui/info.vue   |  4 +-
 .../app/common/views/components/uploader.vue  |  4 +-
 .../app/common/views/components/url.vue       |  4 +-
 .../views/components/visibility-chooser.vue   | 10 +-
 src/client/app/common/views/pages/follow.vue  | 12 +--
 .../app/common/views/widgets/donation.vue     |  4 +-
 .../app/common/views/widgets/hashtags.vue     |  2 +-
 src/client/app/common/views/widgets/memo.vue  |  2 +-
 .../app/common/views/widgets/photo-stream.vue |  6 +-
 .../common/views/widgets/posts-monitor.vue    |  4 +-
 src/client/app/common/views/widgets/rss.vue   |  8 +-
 .../app/common/views/widgets/server.cpu.vue   |  4 +-
 .../app/common/views/widgets/server.disk.vue  |  4 +-
 .../common/views/widgets/server.memory.vue    |  4 +-
 .../app/common/views/widgets/server.vue       |  8 +-
 src/client/app/common/views/widgets/tips.vue  |  4 +-
 .../app/desktop/views/components/activity.vue |  8 +-
 .../app/desktop/views/components/calendar.vue |  6 +-
 .../choose-file-from-drive-window.vue         |  6 +-
 .../choose-folder-from-drive-window.vue       |  4 +-
 .../views/components/context-menu.menu.vue    | 14 +--
 .../desktop/views/components/crop-window.vue  |  4 +-
 .../app/desktop/views/components/dialog.vue   |  2 -
 .../desktop/views/components/drive-window.vue |  4 +-
 .../desktop/views/components/drive.file.vue   | 12 +--
 .../desktop/views/components/drive.folder.vue | 16 +--
 .../views/components/drive.nav-folder.vue     |  4 +-
 .../app/desktop/views/components/drive.vue    | 19 ++--
 .../views/components/follow-button.vue        | 12 +--
 .../views/components/friends-maker.vue        |  8 +-
 .../desktop/views/components/game-window.vue  |  4 +-
 .../app/desktop/views/components/home.vue     |  6 +-
 .../desktop/views/components/input-dialog.vue |  6 +-
 .../desktop/views/components/media-image.vue  |  2 +-
 .../desktop/views/components/media-video.vue  |  4 +-
 .../components/messaging-room-window.vue      |  4 +-
 .../views/components/messaging-window.vue     |  4 +-
 .../desktop/views/components/note-detail.vue  | 20 ++--
 .../app/desktop/views/components/note.vue     | 18 ++--
 .../app/desktop/views/components/notes.vue    |  8 +-
 .../views/components/notifications.vue        | 32 +++---
 .../views/components/post-form-window.vue     |  2 +-
 .../desktop/views/components/post-form.vue    | 22 ++---
 .../received-follow-requests-window.vue       |  2 +-
 .../views/components/renote-form-window.vue   |  4 +-
 .../views/components/settings-window.vue      |  4 +-
 .../desktop/views/components/settings.2fa.vue |  2 +-
 .../views/components/settings.signins.vue     |  8 +-
 .../app/desktop/views/components/settings.vue | 64 ++++++------
 .../views/components/sub-note-content.vue     |  2 +-
 .../views/components/timeline.core.vue        |  4 +-
 .../app/desktop/views/components/timeline.vue | 28 +++---
 .../views/components/ui.header.account.vue    | 67 ++++++++++---
 .../views/components/ui.header.nav.vue        | 20 ++--
 .../components/ui.header.notifications.vue    |  7 +-
 .../views/components/ui.header.post.vue       |  2 +-
 .../views/components/ui.header.search.vue     |  4 +-
 .../desktop/views/components/ui.sidebar.vue   | 28 +++---
 .../views/components/user-lists-window.vue    |  2 +-
 .../desktop/views/components/users-list.vue   |  4 +-
 .../views/components/widget-container.vue     |  2 +-
 .../app/desktop/views/components/window.vue   | 11 ++-
 .../desktop/views/pages/deck/deck.column.vue  | 26 ++---
 .../views/pages/deck/deck.direct-column.vue   |  2 +-
 .../views/pages/deck/deck.hashtag-column.vue  |  2 +-
 .../views/pages/deck/deck.mentions-column.vue |  2 +-
 .../views/pages/deck/deck.note-column.vue     |  4 +-
 .../desktop/views/pages/deck/deck.notes.vue   |  8 +-
 .../views/pages/deck/deck.notification.vue    | 18 ++--
 .../pages/deck/deck.notifications-column.vue  |  2 +-
 .../views/pages/deck/deck.notifications.vue   | 10 +-
 .../views/pages/deck/deck.tl-column.vue       | 14 +--
 .../views/pages/deck/deck.user-column.vue     | 28 +++---
 .../app/desktop/views/pages/deck/deck.vue     | 22 ++---
 .../views/pages/deck/deck.widgets-column.vue  |  6 +-
 src/client/app/desktop/views/pages/note.vue   |  4 +-
 src/client/app/desktop/views/pages/search.vue |  7 +-
 .../app/desktop/views/pages/selectdrive.vue   |  2 +-
 src/client/app/desktop/views/pages/share.vue  |  2 +-
 src/client/app/desktop/views/pages/tag.vue    |  4 +-
 .../pages/user/user.followers-you-know.vue    |  4 +-
 .../desktop/views/pages/user/user.friends.vue |  4 +-
 .../desktop/views/pages/user/user.github.vue  |  2 +-
 .../desktop/views/pages/user/user.header.vue  |  6 +-
 .../desktop/views/pages/user/user.photos.vue  |  4 +-
 .../desktop/views/pages/user/user.profile.vue | 14 +--
 .../views/pages/user/user.timeline.vue        | 10 +-
 .../desktop/views/pages/user/user.twitter.vue |  2 +-
 .../app/desktop/views/pages/user/user.vue     |  4 +-
 .../app/desktop/views/pages/welcome.vue       | 16 +--
 .../app/desktop/views/widgets/messaging.vue   |  4 +-
 .../desktop/views/widgets/notifications.vue   |  4 +-
 .../app/desktop/views/widgets/polls.vue       | 10 +-
 .../app/desktop/views/widgets/post-form.vue   |  4 +-
 .../app/desktop/views/widgets/trends.vue      |  8 +-
 .../app/desktop/views/widgets/users.vue       |  8 +-
 src/client/app/dev/views/new-app.vue          |  2 +-
 src/client/app/init.ts                        | 99 ++++++++++++++++++-
 .../app/mobile/views/components/dialog.vue    |  2 -
 .../views/components/drive-file-chooser.vue   |  4 +-
 .../views/components/drive-folder-chooser.vue |  4 +-
 .../views/components/drive.file-detail.vue    | 24 ++---
 .../mobile/views/components/drive.file.vue    |  6 +-
 .../mobile/views/components/drive.folder.vue  |  6 +-
 .../app/mobile/views/components/drive.vue     | 10 +-
 .../mobile/views/components/follow-button.vue | 12 +--
 .../mobile/views/components/friends-maker.vue |  8 +-
 .../mobile/views/components/media-image.vue   |  2 +-
 .../mobile/views/components/media-video.vue   |  4 +-
 .../mobile/views/components/note-detail.vue   | 20 ++--
 .../app/mobile/views/components/note.vue      | 18 ++--
 .../app/mobile/views/components/notes.vue     | 10 +-
 .../views/components/notification-preview.vue | 22 ++---
 .../mobile/views/components/notification.vue  | 18 ++--
 .../mobile/views/components/notifications.vue | 10 +-
 .../app/mobile/views/components/post-form.vue | 26 ++---
 .../views/components/sub-note-content.vue     |  2 +-
 .../app/mobile/views/components/ui.header.vue |  8 +-
 .../app/mobile/views/components/ui.nav.vue    | 34 +++----
 .../mobile/views/components/user-timeline.vue |  2 +-
 .../mobile/views/components/users-list.vue    |  4 +-
 .../views/components/widget-container.vue     |  2 +-
 src/client/app/mobile/views/pages/drive.vue   |  6 +-
 .../app/mobile/views/pages/favorites.vue      |  2 +-
 .../app/mobile/views/pages/games/reversi.vue  |  2 +-
 .../app/mobile/views/pages/home.timeline.vue  |  2 +-
 src/client/app/mobile/views/pages/home.vue    | 42 ++++----
 .../app/mobile/views/pages/messaging-room.vue |  2 +-
 .../app/mobile/views/pages/messaging.vue      |  2 +-
 src/client/app/mobile/views/pages/note.vue    |  6 +-
 .../app/mobile/views/pages/notifications.vue  |  4 +-
 .../views/pages/received-follow-requests.vue  |  2 +-
 src/client/app/mobile/views/pages/search.vue  |  4 +-
 .../app/mobile/views/pages/selectdrive.vue    |  4 +-
 .../app/mobile/views/pages/settings.vue       | 22 ++---
 src/client/app/mobile/views/pages/share.vue   |  2 +-
 src/client/app/mobile/views/pages/tag.vue     |  4 +-
 .../app/mobile/views/pages/user-list.vue      |  2 +-
 .../app/mobile/views/pages/user-lists.vue     |  4 +-
 src/client/app/mobile/views/pages/user.vue    | 20 ++--
 .../pages/user/home.followers-you-know.vue    |  2 +-
 .../mobile/views/pages/user/home.friends.vue  |  2 +-
 .../mobile/views/pages/user/home.notes.vue    |  2 +-
 .../mobile/views/pages/user/home.photos.vue   |  2 +-
 .../app/mobile/views/pages/user/home.vue      | 10 +-
 src/client/app/mobile/views/pages/welcome.vue |  4 +-
 src/client/app/mobile/views/pages/widgets.vue |  6 +-
 .../app/mobile/views/widgets/activity.vue     |  2 +-
 src/docs/ui.styl                              |  2 +-
 src/misc/fa.ts                                | 54 ----------
 src/server/web/index.ts                       |  4 +-
 webpack.config.ts                             | 18 ----
 190 files changed, 924 insertions(+), 865 deletions(-)
 delete mode 100644 src/misc/fa.ts

diff --git a/gulpfile.ts b/gulpfile.ts
index c47d90a1c..029979c35 100644
--- a/gulpfile.ts
+++ b/gulpfile.ts
@@ -21,7 +21,6 @@ import * as htmlmin from 'gulp-htmlmin';
 const uglifyes = require('uglify-es');
 
 const locales = require('./locales');
-import { fa } from './src/misc/fa';
 
 const uglify = uglifyComposer(uglifyes, console);
 
@@ -164,8 +163,7 @@ gulp.task('build:client:pug', [
 		gulp.src('./src/client/app/base.pug')
 			.pipe(pug({
 				locals: {
-					themeColor: constants.themeColor,
-					facss: fa.dom.css()
+					themeColor: constants.themeColor
 				}
 			}))
 			.pipe(htmlmin({
diff --git a/package.json b/package.json
index d1c846b86..bfa7ca193 100644
--- a/package.json
+++ b/package.json
@@ -20,10 +20,11 @@
 		"format": "gulp format"
 	},
 	"dependencies": {
-		"@fortawesome/fontawesome-svg-core": "1.2.6",
-		"@fortawesome/free-brands-svg-icons": "5.4.1",
-		"@fortawesome/free-regular-svg-icons": "5.4.1",
-		"@fortawesome/free-solid-svg-icons": "5.4.1",
+		"@fortawesome/fontawesome-svg-core": "1.2.8",
+		"@fortawesome/free-brands-svg-icons": "5.5.0",
+		"@fortawesome/free-regular-svg-icons": "5.5.0",
+		"@fortawesome/free-solid-svg-icons": "5.5.0",
+		"@fortawesome/vue-fontawesome": "0.1.2",
 		"@koa/cors": "2.2.2",
 		"@prezzemolo/rap": "0.1.2",
 		"@prezzemolo/zip": "0.0.3",
@@ -215,7 +216,6 @@
 		"vue-content-loading": "1.5.3",
 		"vue-cropperjs": "2.2.2",
 		"vue-js-modal": "1.3.26",
-		"vue-json-tree-view": "2.1.4",
 		"vue-loader": "15.4.2",
 		"vue-router": "3.0.1",
 		"vue-style-loader": "4.1.2",
diff --git a/src/client/app/admin/views/announcements.vue b/src/client/app/admin/views/announcements.vue
index bd99e1bc0..cc765230a 100644
--- a/src/client/app/admin/views/announcements.vue
+++ b/src/client/app/admin/views/announcements.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="cdeuzmsthagexbkpofbmatmugjuvogfb">
 	<ui-card>
-		<div slot="title">%fa:broadcast-tower% %i18n:@announcements%</div>
+		<div slot="title"><fa icon="broadcast-tower"/> %i18n:@announcements%</div>
 		<section v-for="(announcement, i) in announcements" class="fit-top">
 			<ui-input v-model="announcement.title" @change="save">
 				<span>%i18n:@title%</span>
@@ -15,7 +15,7 @@
 			</ui-horizon-group>
 		</section>
 		<section>
-			<ui-button @click="add">%fa:plus% %i18n:@add%</ui-button>
+			<ui-button @click="add"><fa icon="plus"/> %i18n:@add%</ui-button>
 		</section>
 	</ui-card>
 </div>
diff --git a/src/client/app/admin/views/ap-log.vue b/src/client/app/admin/views/ap-log.vue
index 6bcffca5e..1038e0a46 100644
--- a/src/client/app/admin/views/ap-log.vue
+++ b/src/client/app/admin/views/ap-log.vue
@@ -3,10 +3,10 @@
 	<table>
 		<thead>
 			<tr>
-				<th>%fa:exchange-alt% In/Out</th>
-				<th>%fa:server% Host</th>
-				<th>%fa:bolt% Activity</th>
-				<th>%fa:user% Actor</th>
+				<th><fa icon="exchange-alt"/> In/Out</th>
+				<th><fa icon="server"/> Host</th>
+				<th><fa icon="bolt"/> Activity</th>
+				<th><fa icon="user"/> Actor</th>
 			</tr>
 		</thead>
 		<tbody>
diff --git a/src/client/app/admin/views/charts.vue b/src/client/app/admin/views/charts.vue
index 041f419cf..069c35746 100644
--- a/src/client/app/admin/views/charts.vue
+++ b/src/client/app/admin/views/charts.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="qvgidhudpqhjttdhxubzuyrhyzgslujw">
 	<header>
-		<b>%fa:chart-bar R% %i18n:@title%:</b>
+		<b><fa :icon="['far', 'chart-bar']"/> %i18n:@title%:</b>
 		<select v-model="src">
 			<optgroup label="%i18n:@federation%">
 				<option value="federation-instances">%i18n:@charts.federation-instances%</option>
diff --git a/src/client/app/admin/views/cpu-memory.vue b/src/client/app/admin/views/cpu-memory.vue
index eb0fc0b42..999908fd2 100644
--- a/src/client/app/admin/views/cpu-memory.vue
+++ b/src/client/app/admin/views/cpu-memory.vue
@@ -2,14 +2,14 @@
 <div class="zyknedwtlthezamcjlolyusmipqmjgxz">
 	<div>
 		<header>
-			<span>%fa:microchip% CPU <span>{{ cpuP }}%</span></span>
+			<span><fa icon="microchip"/> CPU <span>{{ cpuP }}%</span></span>
 			<span v-if="meta">{{ meta.cpu.model }}</span>
 		</header>
 		<div ref="cpu"></div>
 	</div>
 	<div>
 		<header>
-			<span>%fa:memory% MEM <span>{{ memP }}%</span></span>
+			<span><fa icon="memory"/> MEM <span>{{ memP }}%</span></span>
 			<span v-if="meta"></span>
 		</header>
 		<div ref="mem"></div>
diff --git a/src/client/app/admin/views/dashboard.vue b/src/client/app/admin/views/dashboard.vue
index 6f30b54c7..383b85926 100644
--- a/src/client/app/admin/views/dashboard.vue
+++ b/src/client/app/admin/views/dashboard.vue
@@ -11,54 +11,54 @@
 	<div v-if="stats" class="stats">
 		<div>
 			<div>
-				<div>%fa:user%</div>
+				<div><fa icon="user"/></div>
 				<div>
 					<span>%i18n:@accounts%</span>
 					<b class="primary">{{ stats.originalUsersCount | number }}</b>
 				</div>
 			</div>
 			<div>
-				<span>%fa:home% %i18n:@this-instance%</span>
-				<span @click="setChartSrc('users')">%fa:chart-bar R%</span>
+				<span><fa icon="home"/> %i18n:@this-instance%</span>
+				<span @click="setChartSrc('users')"><fa :icon="['far', 'chart-bar']"/></span>
 			</div>
 		</div>
 		<div>
 			<div>
-				<div>%fa:pencil-alt%</div>
+				<div><fa icon="pencil-alt"/></div>
 				<div>
 					<span>%i18n:@notes%</span>
 					<b class="primary">{{ stats.originalNotesCount | number }}</b>
 				</div>
 			</div>
 			<div>
-				<span>%fa:home% %i18n:@this-instance%</span>
-				<span @click="setChartSrc('notes')">%fa:chart-bar R%</span>
+				<span><fa icon="home"/> %i18n:@this-instance%</span>
+				<span @click="setChartSrc('notes')"><fa :icon="['far', 'chart-bar']"/></span>
 			</div>
 		</div>
 		<div>
 			<div>
-				<div>%fa:database%</div>
+				<div><fa icon="database"/></div>
 				<div>
 					<span>%i18n:@drive%</span>
 					<b>{{ stats.driveUsageLocal | bytes }}</b>
 				</div>
 			</div>
 			<div>
-				<span>%fa:home% %i18n:@this-instance%</span>
-				<span @click="setChartSrc('drive')">%fa:chart-bar R%</span>
+				<span><fa icon="home"/> %i18n:@this-instance%</span>
+				<span @click="setChartSrc('drive')"><fa :icon="['far', 'chart-bar']"/></span>
 			</div>
 		</div>
 		<div>
 			<div>
-				<div>%fa:hdd R%</div>
+				<div><fa :icon="['far', 'hdd']"/></div>
 				<div>
 					<span>%i18n:@instances%</span>
 					<b>{{ stats.instances | number }}</b>
 				</div>
 			</div>
 			<div>
-				<span>%fa:globe% %i18n:@federated%</span>
-				<span @click="setChartSrc('federation-instances-total')">%fa:chart-bar R%</span>
+				<span><fa icon="globe"/> %i18n:@federated%</span>
+				<span @click="setChartSrc('federation-instances-total')"><fa :icon="['far', 'chart-bar']"/></span>
 			</div>
 		</div>
 	</div>
diff --git a/src/client/app/admin/views/emoji.vue b/src/client/app/admin/views/emoji.vue
index 5a4df29cb..a69792cc0 100644
--- a/src/client/app/admin/views/emoji.vue
+++ b/src/client/app/admin/views/emoji.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="tumhkfkmgtvzljezfvmgkeurkfncshbe">
 	<ui-card>
-		<div slot="title">%fa:plus% %i18n:@add-emoji.title%</div>
+		<div slot="title"><fa icon="plus"/> %i18n:@add-emoji.title%</div>
 		<section class="fit-top">
 			<ui-horizon-group inputs>
 				<ui-input v-model="name">
@@ -22,7 +22,7 @@
 	</ui-card>
 
 	<ui-card>
-		<div slot="title">%fa:grin R% %i18n:@emojis.title%</div>
+		<div slot="title"><fa :icon="['far', 'grin']"/> %i18n:@emojis.title%</div>
 		<section v-for="emoji in emojis">
 			<img :src="emoji.url" :alt="emoji.name" style="width: 64px;"/>
 			<ui-horizon-group inputs>
@@ -37,8 +37,8 @@
 				<span>%i18n:@add-emoji.url%</span>
 			</ui-input>
 			<ui-horizon-group>
-				<ui-button @click="updateEmoji(emoji)">%fa:save R% %i18n:@emojis.update%</ui-button>
-				<ui-button @click="removeEmoji(emoji)">%fa:trash-alt R% %i18n:@emojis.remove%</ui-button>
+				<ui-button @click="updateEmoji(emoji)"><fa :icon="['far', 'save']"/> %i18n:@emojis.update%</ui-button>
+				<ui-button @click="removeEmoji(emoji)"><fa :icon="['far', 'trash-alt']"/> %i18n:@emojis.remove%</ui-button>
 			</ui-horizon-group>
 		</section>
 	</ui-card>
diff --git a/src/client/app/admin/views/index.vue b/src/client/app/admin/views/index.vue
index 56b825e6f..8cfcd2b3a 100644
--- a/src/client/app/admin/views/index.vue
+++ b/src/client/app/admin/views/index.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mk-admin" :class="{ isMobile }">
 	<header v-show="isMobile">
-		<button class="nav" @click="navOpend = true">%fa:bars%</button>
+		<button class="nav" @click="navOpend = true"><fa icon="bars"/></button>
 		<span>MisskeyMyAdmin</span>
 	</header>
 	<div class="nav-backdrop"
@@ -18,18 +18,18 @@
 			<p class="name">{{ $store.state.i | userName }}</p>
 		</div>
 		<ul>
-			<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }">%fa:home .fw%%i18n:@dashboard%</li>
-			<li @click="nav('instance')" :class="{ active: page == 'instance' }">%fa:cog .fw%%i18n:@instance%</li>
-			<li @click="nav('users')" :class="{ active: page == 'users' }">%fa:users .fw%%i18n:@users%</li>
-			<li @click="nav('emoji')" :class="{ active: page == 'emoji' }">%fa:grin R .fw%%i18n:@emoji%</li>
-			<li @click="nav('announcements')" :class="{ active: page == 'announcements' }">%fa:broadcast-tower .fw%%i18n:@announcements%</li>
-			<li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }">%fa:hashtag .fw%%i18n:@hashtags%</li>
+			<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }"><fa icon="home" fixed-width/>%i18n:@dashboard%</li>
+			<li @click="nav('instance')" :class="{ active: page == 'instance' }"><fa icon="cog" fixed-width/>%i18n:@instance%</li>
+			<li @click="nav('users')" :class="{ active: page == 'users' }"><fa icon="users" fixed-width/>%i18n:@users%</li>
+			<li @click="nav('emoji')" :class="{ active: page == 'emoji' }"><fa icon="grin R" fixed-width/>%i18n:@emoji%</li>
+			<li @click="nav('announcements')" :class="{ active: page == 'announcements' }"><fa icon="broadcast-tower" fixed-width/>%i18n:@announcements%</li>
+			<li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }"><fa icon="hashtag" fixed-width/>%i18n:@hashtags%</li>
 
-			<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }">%fa:cloud .fw%%i18n:common.drive%</li> -->
+			<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }"><fa icon="cloud" fixed-width/>%i18n:common.drive%</li> -->
 			<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> -->
 		</ul>
 		<div class="back-to-misskey">
-			<a href="/">%fa:arrow-left% %i18n:@back-to-misskey%</a>
+			<a href="/"><fa icon="arrow-left"/> %i18n:@back-to-misskey%</a>
 		</div>
 		<div class="version">
 			<small>Misskey {{ version }}</small>
@@ -126,7 +126,7 @@ export default Vue.extend({
 			line-height $headerHeight
 			border-right solid 1px rgba(#000, 0.1)
 
-			> [data-fa]
+			> [data-icon]
 				transition all 0.2s ease
 
 	> nav
@@ -188,7 +188,7 @@ export default Vue.extend({
 				&:hover
 					color #fff
 
-				> [data-fa]
+				> [data-icon]
 					margin-right 6px
 
 		> .version
@@ -218,7 +218,7 @@ export default Vue.extend({
 				&:hover
 					color #fff
 
-				> [data-fa]
+				> [data-icon]
 					margin-right 6px
 
 				&.active
diff --git a/src/client/app/app.styl b/src/client/app/app.styl
index 725147f25..ff8380401 100644
--- a/src/client/app/app.styl
+++ b/src/client/app/app.styl
@@ -128,7 +128,7 @@ pre
 		overflow auto
 		tab-size 2
 
-[data-fa]
+[data-icon]
 	display inline-block
 
 .swal2-container
diff --git a/src/client/app/common/views/components/api-settings.vue b/src/client/app/common/views/components/api-settings.vue
index e7cc6e7a8..15b2d0085 100644
--- a/src/client/app/common/views/components/api-settings.vue
+++ b/src/client/app/common/views/components/api-settings.vue
@@ -1,6 +1,6 @@
 <template>
 <ui-card>
-	<div slot="title">%fa:key% API</div>
+	<div slot="title"><fa icon="key"/> API</div>
 
 	<section class="fit-top">
 		<ui-input :value="$store.state.i.token" readonly>
@@ -9,11 +9,11 @@
 		<p>%i18n:@intro%</p>
 		<ui-info warn>%i18n:@caution%</ui-info>
 		<p>%i18n:@regeneration-of-token%</p>
-		<ui-button @click="regenerateToken">%fa:sync-alt% %i18n:@regenerate-token%</ui-button>
+		<ui-button @click="regenerateToken"><fa icon="sync-alt"/> %i18n:@regenerate-token%</ui-button>
 	</section>
 
 	<section>
-		<header>%fa:terminal% %i18n:@console.title%</header>
+		<header><fa icon="terminal"/> %i18n:@console.title%</header>
 		<ui-input v-model="endpoint">
 			<span>%i18n:@console.endpoint%</span>
 		</ui-input>
@@ -22,7 +22,7 @@
 		</ui-textarea>
 		<ui-button @click="send" :disabled="sending">
 			<template v-if="sending">%i18n:@console.sending%</template>
-			<template v-else>%fa:paper-plane% %i18n:@console.send%</template>
+			<template v-else><fa icon="paper-plane"/> %i18n:@console.send%</template>
 		</ui-button>
 		<ui-textarea v-if="res" v-model="res" readonly tall>
 			<span>%i18n:@console.response%</span>
diff --git a/src/client/app/common/views/components/connect-failed.troubleshooter.vue b/src/client/app/common/views/components/connect-failed.troubleshooter.vue
index f64cae6b4..544bb7eaa 100644
--- a/src/client/app/common/views/components/connect-failed.troubleshooter.vue
+++ b/src/client/app/common/views/components/connect-failed.troubleshooter.vue
@@ -1,35 +1,35 @@
 <template>
 <div class="troubleshooter">
 	<div class="body">
-		<h1>%fa:wrench%%i18n:@title%</h1>
+		<h1><fa icon="wrench"/>%i18n:@title%</h1>
 		<div>
 			<p :data-wip="network == null">
 				<template v-if="network != null">
-					<template v-if="network">%fa:check%</template>
-					<template v-if="!network">%fa:times%</template>
+					<template v-if="network"><fa icon="check"/></template>
+					<template v-if="!network"><fa icon="times"/></template>
 				</template>
 				{{ network == null ? '%i18n:@checking-network%' : '%i18n:@network%' }}<mk-ellipsis v-if="network == null"/>
 			</p>
 			<p v-if="network == true" :data-wip="internet == null">
 				<template v-if="internet != null">
-					<template v-if="internet">%fa:check%</template>
-					<template v-if="!internet">%fa:times%</template>
+					<template v-if="internet"><fa icon="check"/></template>
+					<template v-if="!internet"><fa icon="times"/></template>
 				</template>
 				{{ internet == null ? '%i18n:@checking-internet%' : '%i18n:@internet%' }}<mk-ellipsis v-if="internet == null"/>
 			</p>
 			<p v-if="internet == true" :data-wip="server == null">
 				<template v-if="server != null">
-					<template v-if="server">%fa:check%</template>
-					<template v-if="!server">%fa:times%</template>
+					<template v-if="server"><fa icon="check"/></template>
+					<template v-if="!server"><fa icon="times"/></template>
 				</template>
 				{{ server == null ? '%i18n:@checking-server%' : '%i18n:@server%' }}<mk-ellipsis v-if="server == null"/>
 			</p>
 		</div>
 		<p v-if="!end">%i18n:@finding%<mk-ellipsis/></p>
-		<p v-if="network === false"><b>%fa:exclamation-triangle%%i18n:@no-network%</b><br>%i18n:@no-network-desc%</p>
-		<p v-if="internet === false"><b>%fa:exclamation-triangle%%i18n:@no-internet%</b><br>%i18n:@no-internet-desc%</p>
-		<p v-if="server === false"><b>%fa:exclamation-triangle%%i18n:@no-server%</b><br>%i18n:@no-server-desc%</p>
-		<p v-if="server === true" class="success"><b>%fa:info-circle%%i18n:@success%</b><br>%i18n:@success-desc%</p>
+		<p v-if="network === false"><b><fa icon="exclamation-triangle"/>%i18n:@no-network%</b><br>%i18n:@no-network-desc%</p>
+		<p v-if="internet === false"><b><fa icon="exclamation-triangle"/>%i18n:@no-internet%</b><br>%i18n:@no-internet-desc%</p>
+		<p v-if="server === false"><b><fa icon="exclamation-triangle"/>%i18n:@no-server%</b><br>%i18n:@no-server-desc%</p>
+		<p v-if="server === true" class="success"><b><fa icon="info-circle"/>%i18n:@success%</b><br>%i18n:@success-desc%</p>
 	</div>
 	<footer>
 		<a href="/assets/flush.html">%i18n:@flush%</a> | <a href="/assets/version.html">%i18n:@set-version%</a>
@@ -100,7 +100,7 @@ export default Vue.extend({
 			color #444
 			border-bottom solid 1px #eee
 
-			> [data-fa]
+			> [data-icon]
 				margin-right 0.25em
 
 		> div
@@ -115,7 +115,7 @@ export default Vue.extend({
 				&[data-wip]
 					color #888
 
-				> [data-fa]
+				> [data-icon]
 					margin-right 0.25em
 
 					&.times
@@ -132,7 +132,7 @@ export default Vue.extend({
 			border-top solid 1px #eee
 
 			> b
-				> [data-fa]
+				> [data-icon]
 					margin-right 0.25em
 
 			&.success
diff --git a/src/client/app/common/views/components/connect-failed.vue b/src/client/app/common/views/components/connect-failed.vue
index 36cae0566..8567f9a15 100644
--- a/src/client/app/common/views/components/connect-failed.vue
+++ b/src/client/app/common/views/components/connect-failed.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="mk-connect-failed">
-	<img src="data:image/jpeg;base64,%base64:/assets/error.jpg%" alt=""/>
+	<img src="https://raw.githubusercontent.com/syuilo/misskey/develop/src/client/assets/error.jpg" alt=""/>
 	<h1>%i18n:@title%</h1>
 	<p class="text">
 		<span>{{ '%i18n:@description%'.substr(0, '%i18n:@description%'.indexOf('{')) }}</span>
diff --git a/src/client/app/common/views/components/drive-settings.vue b/src/client/app/common/views/components/drive-settings.vue
index 3b45a6873..1d0da3a53 100644
--- a/src/client/app/common/views/components/drive-settings.vue
+++ b/src/client/app/common/views/components/drive-settings.vue
@@ -1,6 +1,6 @@
 <template>
 <ui-card>
-	<div slot="title">%fa:cloud% %i18n:common.drive%</div>
+	<div slot="title"><fa icon="cloud"/> %i18n:common.drive%</div>
 
 	<section v-if="!fetching" class="juakhbxthdewydyreaphkepoxgxvfogn">
 		<div class="meter"><div :style="meterStyle"></div></div>
diff --git a/src/client/app/common/views/components/error.vue b/src/client/app/common/views/components/error.vue
index 7381cf537..902e4f31d 100644
--- a/src/client/app/common/views/components/error.vue
+++ b/src/client/app/common/views/components/error.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="wjqjnyhzogztorhrdgcpqlkxhkmuetgj">
-	<p>%fa:exclamation-triangle% %i18n:common.error.title%</p>
+	<p><fa icon="exclamation-triangle"/> %i18n:common.error.title%</p>
 	<ui-button @click="() => $emit('retry')">%i18n:common.error.retry%</ui-button>
 </div>
 </template>
diff --git a/src/client/app/common/views/components/file-type-icon.vue b/src/client/app/common/views/components/file-type-icon.vue
index b7e868d1f..3a9fe768d 100644
--- a/src/client/app/common/views/components/file-type-icon.vue
+++ b/src/client/app/common/views/components/file-type-icon.vue
@@ -1,6 +1,6 @@
 <template>
 <span class="mk-file-type-icon">
-	<template v-if="kind == 'image'">%fa:file-image%</template>
+	<template v-if="kind == 'image'"><fa icon="file-image"/></template>
 </span>
 </template>
 
diff --git a/src/client/app/common/views/components/games/reversi/reversi.game.vue b/src/client/app/common/views/components/games/reversi/reversi.game.vue
index 608e1c182..b2cf8b4d9 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.game.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.game.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="xqnhankfuuilcwvhgsopeqncafzsquya">
-	<button class="go-index" v-if="selfNav" @click="goIndex">%fa:arrow-left%</button>
+	<button class="go-index" v-if="selfNav" @click="goIndex"><fa icon="arrow-left"/></button>
 	<header><b><router-link :to="blackUser | userPage">{{ blackUser | userName }}</router-link></b>(%i18n:common.reversi.black%) vs <b><router-link :to="whiteUser | userPage">{{ whiteUser | userName }}</router-link></b>(%i18n:common.reversi.white%)</header>
 
 	<div style="overflow: hidden; line-height: 28px;">
@@ -51,13 +51,13 @@
 
 	<div class="player" v-if="game.isEnded">
 		<div>
-			<button @click="logPos = 0" :disabled="logPos == 0">%fa:angle-double-left%</button>
-			<button @click="logPos--" :disabled="logPos == 0">%fa:angle-left%</button>
+			<button @click="logPos = 0" :disabled="logPos == 0"><fa icon="angle-double-left"/></button>
+			<button @click="logPos--" :disabled="logPos == 0"><fa icon="angle-left"/></button>
 		</div>
 		<span>{{ logPos }} / {{ logs.length }}</span>
 		<div>
-			<button @click="logPos++" :disabled="logPos == logs.length">%fa:angle-right%</button>
-			<button @click="logPos = logs.length" :disabled="logPos == logs.length">%fa:angle-double-right%</button>
+			<button @click="logPos++" :disabled="logPos == logs.length"><fa icon="angle-right"/></button>
+			<button @click="logPos = logs.length" :disabled="logPos == logs.length"><fa icon="angle-double-right"/></button>
 		</div>
 	</div>
 
diff --git a/src/client/app/common/views/components/games/reversi/reversi.room.vue b/src/client/app/common/views/components/games/reversi/reversi.room.vue
index 29c6794f6..7571d69af 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.room.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.room.vue
@@ -17,13 +17,13 @@
 			</header>
 
 			<div>
-				<div class="random" v-if="game.settings.map == null">%fa:dice%</div>
+				<div class="random" v-if="game.settings.map == null"><fa icon="dice"/></div>
 				<div class="board" v-else :style="{ 'grid-template-rows': `repeat(${ game.settings.map.length }, 1fr)`, 'grid-template-columns': `repeat(${ game.settings.map[0].length }, 1fr)` }">
 					<div v-for="(x, i) in game.settings.map.join('')"
 							:data-none="x == ' '"
 							@click="onPixelClick(i, x)">
-						<template v-if="x == 'b'"><template v-if="$store.state.device.darkmode">%fa:circle R%</template><template v-else>%fa:circle%</template></template>
-						<template v-if="x == 'w'"><template v-if="$store.state.device.darkmode">%fa:circle%</template><template v-else>%fa:circle R%</template></template>
+						<template v-if="x == 'b'"><template v-if="$store.state.device.darkmode"><fa :icon="['far', 'circle']"/></template><template v-else><fa icon="circle"/></template></template>
+						<template v-if="x == 'w'"><template v-if="$store.state.device.darkmode"><fa :icon="['far', 'circle']"/></template><template v-else><fa icon="circle"/></template></template>
 					</div>
 				</div>
 			</div>
diff --git a/src/client/app/common/views/components/google.vue b/src/client/app/common/views/components/google.vue
index ac71a5e56..1d710bc3c 100644
--- a/src/client/app/common/views/components/google.vue
+++ b/src/client/app/common/views/components/google.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mk-google">
 	<input type="search" v-model="query" :placeholder="q">
-	<button @click="search">%fa:search% %i18n:common.search%</button>
+	<button @click="search"><fa icon="search"/> %i18n:common.search%</button>
 </div>
 </template>
 
diff --git a/src/client/app/common/views/components/media-banner.vue b/src/client/app/common/views/components/media-banner.vue
index 0f5981d3c..00a7f22e4 100644
--- a/src/client/app/common/views/components/media-banner.vue
+++ b/src/client/app/common/views/components/media-banner.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mk-media-banner">
 	<div class="sensitive" v-if="media.isSensitive && hide" @click="hide = false">
-		<span class="icon">%fa:exclamation-triangle%</span>
+		<span class="icon"><fa icon="exclamation-triangle"/></span>
 		<b>%i18n:@sensitive%</b>
 		<span>%i18n:@click-to-show%</span>
 	</div>
@@ -18,7 +18,7 @@
 		:title="media.name"
 		:download="media.name"
 	>
-		<span class="icon">%fa:download%</span>
+		<span class="icon"><fa icon="download"/></span>
 		<b>{{ media.name }}</b>
 	</a>
 </div>
diff --git a/src/client/app/common/views/components/menu.vue b/src/client/app/common/views/components/menu.vue
index be2c03f54..e085bf4bb 100644
--- a/src/client/app/common/views/components/menu.vue
+++ b/src/client/app/common/views/components/menu.vue
@@ -4,7 +4,9 @@
 	<div class="popover" :class="{ hukidasi }" ref="popover">
 		<template v-for="item, i in items">
 			<div v-if="item === null"></div>
-			<button v-if="item" @click="clicked(item.action)" v-html="item.icon ? item.icon + ' ' + item.text : item.text" :tabindex="i"></button>
+			<button v-if="item" @click="clicked(item.action)" :tabindex="i">
+				<fa v-if="item.icon" :icon="item.icon"/>{{ item.text }}
+			</button>
 		</template>
 	</div>
 </div>
@@ -188,6 +190,9 @@ export default Vue.extend({
 				color var(--primaryForeground)
 				background var(--primaryDarken10)
 
+			> [data-icon]
+				margin-right 4px
+
 		> div
 			margin 8px 0
 			height 1px
diff --git a/src/client/app/common/views/components/messaging-room.form.vue b/src/client/app/common/views/components/messaging-room.form.vue
index c93fd7f78..3bd04bdbc 100644
--- a/src/client/app/common/views/components/messaging-room.form.vue
+++ b/src/client/app/common/views/components/messaging-room.form.vue
@@ -14,13 +14,13 @@
 	<div class="file" @click="file = null" v-if="file">{{ file.name }}</div>
 	<mk-uploader ref="uploader" @uploaded="onUploaded"/>
 	<button class="send" @click="send" :disabled="!canSend || sending" title="%i18n:@send%">
-		<template v-if="!sending">%fa:paper-plane%</template><template v-if="sending">%fa:spinner .spin%</template>
+		<template v-if="!sending"><fa icon="paper-plane"/></template><template v-if="sending"><fa icon="spinner .spin"/></template>
 	</button>
 	<button class="attach-from-local" @click="chooseFile" title="%i18n:@attach-from-local%">
-		%fa:upload%
+		<fa icon="upload"/>
 	</button>
 	<button class="attach-from-drive" @click="chooseFileFromDrive" title="%i18n:@attach-from-drive%">
-		%fa:R folder-open%
+		<fa :icon="['far', 'folder-open']"/>
 	</button>
 	<input ref="file" type="file" @change="onChangeFile"/>
 </div>
diff --git a/src/client/app/common/views/components/messaging-room.message.vue b/src/client/app/common/views/components/messaging-room.message.vue
index 77bf55c52..08540468c 100644
--- a/src/client/app/common/views/components/messaging-room.message.vue
+++ b/src/client/app/common/views/components/messaging-room.message.vue
@@ -24,7 +24,7 @@
 		<footer>
 			<span class="read" v-if="isMe && message.isRead">%i18n:@is-read%</span>
 			<mk-time :time="message.createdAt"/>
-			<template v-if="message.is_edited">%fa:pencil-alt%</template>
+			<template v-if="message.is_edited"><fa icon="pencil-alt"/></template>
 		</footer>
 	</div>
 </div>
@@ -179,7 +179,7 @@ export default Vue.extend({
 			font-size 10px
 			color var(--messagingRoomMessageInfo)
 
-			> [data-fa]
+			> [data-icon]
 				margin-left 4px
 
 	&:not([data-is-me])
diff --git a/src/client/app/common/views/components/messaging-room.vue b/src/client/app/common/views/components/messaging-room.vue
index d982b10a2..577617c49 100644
--- a/src/client/app/common/views/components/messaging-room.vue
+++ b/src/client/app/common/views/components/messaging-room.vue
@@ -4,11 +4,11 @@
 	@drop.prevent.stop="onDrop"
 >
 	<div class="body">
-		<p class="init" v-if="init">%fa:spinner .spin%%i18n:common.loading%</p>
-		<p class="empty" v-if="!init && messages.length == 0">%fa:info-circle%%i18n:@empty%</p>
-		<p class="no-history" v-if="!init && messages.length > 0 && !existMoreMessages">%fa:flag%%i18n:@no-history%</p>
+		<p class="init" v-if="init"><fa icon="spinner .spin"/>%i18n:common.loading%</p>
+		<p class="empty" v-if="!init && messages.length == 0"><fa icon="info-circle"/>%i18n:@empty%</p>
+		<p class="no-history" v-if="!init && messages.length > 0 && !existMoreMessages"><fa icon="flag"/>%i18n:@no-history%</p>
 		<button class="more" :class="{ fetching: fetchingMoreMessages }" v-if="existMoreMessages" @click="fetchMoreMessages" :disabled="fetchingMoreMessages">
-			<template v-if="fetchingMoreMessages">%fa:spinner .pulse .fw%</template>{{ fetchingMoreMessages ? '%i18n:common.loading%' : '%i18n:@more%' }}
+			<template v-if="fetchingMoreMessages"><fa icon="spinner .pulse" fixed-width/></template>{{ fetchingMoreMessages ? '%i18n:common.loading%' : '%i18n:@more%' }}
 		</button>
 		<template v-for="(message, i) in _messages">
 			<x-message :message="message" :key="message.id"/>
@@ -20,7 +20,7 @@
 	<footer>
 		<transition name="fade">
 			<div class="new-message" v-show="showIndicator">
-				<button @click="onIndicatorClick">%fa:arrow-circle-down%%i18n:@new-message%</button>
+				<button @click="onIndicatorClick"><i><fa icon="arrow-circle-down"/></i>%i18n:@new-message%</button>
 			</div>
 		</transition>
 		<x-form :user="user" ref="form"/>
@@ -280,7 +280,7 @@ export default Vue.extend({
 			color var(--messagingRoomInfo)
 			opacity 0.5
 
-			[data-fa]
+			[data-icon]
 				margin-right 4px
 
 		> .no-history
@@ -292,7 +292,7 @@ export default Vue.extend({
 			color var(--messagingRoomInfo)
 			opacity 0.5
 
-			[data-fa]
+			[data-icon]
 				margin-right 4px
 
 		> .more
@@ -313,7 +313,7 @@ export default Vue.extend({
 			&.fetching
 				cursor wait
 
-			> [data-fa]
+			> [data-icon]
 				margin-right 4px
 
 		> .message
@@ -381,7 +381,7 @@ export default Vue.extend({
 				&:active
 					background var(--primaryDarken10)
 
-				> [data-fa]
+				> i
 					position absolute
 					top 0
 					left 10px
diff --git a/src/client/app/common/views/components/messaging.vue b/src/client/app/common/views/components/messaging.vue
index f5b5e232f..fe6c001c8 100644
--- a/src/client/app/common/views/components/messaging.vue
+++ b/src/client/app/common/views/components/messaging.vue
@@ -2,7 +2,7 @@
 <div class="mk-messaging" :data-compact="compact">
 	<div class="search" v-if="!compact" :style="{ top: headerTop + 'px' }">
 		<div class="form">
-			<label for="search-input">%fa:search%</label>
+			<label for="search-input"><i><fa icon="search"/></i></label>
 			<input v-model="q" type="search" @input="search" @keydown="onSearchKeydown" placeholder="%i18n:@search-user%"/>
 		</div>
 		<div class="result">
@@ -45,7 +45,7 @@
 		</template>
 	</div>
 	<p class="no-history" v-if="!fetching && messages.length == 0">%i18n:@no-history%</p>
-	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
+	<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
 </div>
 </template>
 
@@ -213,7 +213,7 @@ export default Vue.extend({
 				width 38px
 				pointer-events none
 
-				> [data-fa]
+				> i
 					display block
 					position absolute
 					top 0
@@ -418,7 +418,7 @@ export default Vue.extend({
 		text-align center
 		color #aaa
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 
 	// TODO: element base media query
diff --git a/src/client/app/common/views/components/mute-and-block.vue b/src/client/app/common/views/components/mute-and-block.vue
index 8aac74c4e..e4627726f 100644
--- a/src/client/app/common/views/components/mute-and-block.vue
+++ b/src/client/app/common/views/components/mute-and-block.vue
@@ -1,6 +1,6 @@
 <template>
 <ui-card>
-	<div slot="title">%fa:ban% %i18n:@mute-and-block%</div>
+	<div slot="title"><fa icon="ban"/> %i18n:@mute-and-block%</div>
 
 	<section>
 		<header>%i18n:@mute%</header>
diff --git a/src/client/app/common/views/components/nav.vue b/src/client/app/common/views/components/nav.vue
index 27e66358e..5ae4486c0 100644
--- a/src/client/app/common/views/components/nav.vue
+++ b/src/client/app/common/views/components/nav.vue
@@ -8,7 +8,7 @@
 	<i>・</i>
 	<a href="/dev">%i18n:@develop%</a>
 	<i>・</i>
-	<a href="https://twitter.com/misskey_xyz" target="_blank">Follow us on %fa:B twitter%</a>
+	<a href="https://twitter.com/misskey_xyz" target="_blank">Follow us on <fa :icon="['fab', 'twitter']"/></a>
 </span>
 </template>
 
diff --git a/src/client/app/common/views/components/note-header.vue b/src/client/app/common/views/components/note-header.vue
index 5966a5c37..4a94e5b6e 100644
--- a/src/client/app/common/views/components/note-header.vue
+++ b/src/client/app/common/views/components/note-header.vue
@@ -6,18 +6,18 @@
 	<span class="is-bot" v-if="note.user.isBot">bot</span>
 	<span class="is-cat" v-if="note.user.isCat">cat</span>
 	<span class="username"><mk-acct :user="note.user"/></span>
-	<span class="is-verified" v-if="note.user.isVerified" title="%i18n:common.verified-user%">%fa:star%</span>
+	<span class="is-verified" v-if="note.user.isVerified" title="%i18n:common.verified-user%"><fa icon="star"/></span>
 	<div class="info">
 		<span class="app" v-if="note.app && !mini">via <b>{{ note.app.name }}</b></span>
-		<span class="mobile" v-if="note.viaMobile">%fa:mobile-alt%</span>
+		<span class="mobile" v-if="note.viaMobile"><fa icon="mobile-alt"/></span>
 		<router-link class="created-at" :to="note | notePage">
 			<mk-time :time="note.createdAt"/>
 		</router-link>
 		<span class="visibility" v-if="note.visibility != 'public'">
-			<template v-if="note.visibility == 'home'">%fa:home%</template>
-			<template v-if="note.visibility == 'followers'">%fa:unlock%</template>
-			<template v-if="note.visibility == 'specified'">%fa:envelope%</template>
-			<template v-if="note.visibility == 'private'">%fa:lock%</template>
+			<template v-if="note.visibility == 'home'"><fa icon="home"/></template>
+			<template v-if="note.visibility == 'followers'"><fa icon="unlock"/></template>
+			<template v-if="note.visibility == 'specified'"><fa icon="envelope"/></template>
+			<template v-if="note.visibility == 'private'"><fa icon="lock"/></template>
 		</span>
 	</div>
 </header>
diff --git a/src/client/app/common/views/components/note-menu.vue b/src/client/app/common/views/components/note-menu.vue
index 6b96974d5..524a3d8fe 100644
--- a/src/client/app/common/views/components/note-menu.vue
+++ b/src/client/app/common/views/components/note-menu.vue
@@ -15,18 +15,18 @@ export default Vue.extend({
 	computed: {
 		items() {
 			const items = [{
-				icon: '%fa:info-circle%',
+				icon: 'info-circle',
 				text: '%i18n:@detail%',
 				action: this.detail
 			}, {
-				icon: '%fa:link%',
+				icon: 'link',
 				text: '%i18n:@copy-link%',
 				action: this.copyLink
 			}];
 
 			if (this.note.uri) {
 				items.push({
-					icon: '%fa:external-link-square-alt%',
+					icon: 'external-link-square-alt',
 					text: '%i18n:@remote%',
 					action: () => {
 						window.open(this.note.uri, '_blank');
@@ -38,13 +38,13 @@ export default Vue.extend({
 
 			if (this.note.isFavorited) {
 				items.push({
-					icon: '%fa:star%',
+					icon: 'star',
 					text: '%i18n:@unfavorite%',
 					action: this.unfavorite
 				});
 			} else {
 				items.push({
-					icon: '%fa:star%',
+					icon: 'star',
 					text: '%i18n:@favorite%',
 					action: this.favorite
 				});
@@ -53,13 +53,13 @@ export default Vue.extend({
 			if (this.note.userId == this.$store.state.i.id) {
 				if ((this.$store.state.i.pinnedNoteIds || []).includes(this.note.id)) {
 					items.push({
-						icon: '%fa:thumbtack%',
+						icon: 'thumbtack',
 						text: '%i18n:@unpin%',
 						action: this.unpin
 					});
 				} else {
 					items.push({
-						icon: '%fa:thumbtack%',
+						icon: 'thumbtack',
 						text: '%i18n:@pin%',
 						action: this.pin
 					});
@@ -69,7 +69,7 @@ export default Vue.extend({
 			if (this.note.userId == this.$store.state.i.id || this.$store.state.i.isAdmin) {
 				items.push(null);
 				items.push({
-					icon: '%fa:trash-alt R%',
+					icon: ['far', 'trash-alt'],
 					text: '%i18n:@delete%',
 					action: this.del
 				});
diff --git a/src/client/app/common/views/components/poll-editor.vue b/src/client/app/common/views/components/poll-editor.vue
index b5c57d48a..2df84a2f8 100644
--- a/src/client/app/common/views/components/poll-editor.vue
+++ b/src/client/app/common/views/components/poll-editor.vue
@@ -1,19 +1,19 @@
 <template>
 <div class="mk-poll-editor">
 	<p class="caution" v-if="choices.length < 2">
-		%fa:exclamation-triangle%%i18n:@no-only-one-choice%
+		<fa icon="exclamation-triangle"/>%i18n:@no-only-one-choice%
 	</p>
 	<ul ref="choices">
 		<li v-for="(choice, i) in choices">
 			<input :value="choice" @input="onInput(i, $event)" :placeholder="'%i18n:@choice-n%'.replace('{}', i + 1)">
 			<button @click="remove(i)" title="%i18n:@remove%">
-				%fa:times%
+				<fa icon="times"/>
 			</button>
 		</li>
 	</ul>
 	<button class="add" v-if="choices.length < 10" @click="add">%i18n:@add%</button>
 	<button class="destroy" @click="destroy" title="%i18n:@destroy%">
-		%fa:times%
+		<fa icon="times"/>
 	</button>
 </div>
 </template>
@@ -76,7 +76,7 @@ export default Vue.extend({
 		font-size 0.8em
 		color #f00
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 
 	> ul
diff --git a/src/client/app/common/views/components/poll.vue b/src/client/app/common/views/components/poll.vue
index 0dc2622f9..0550fd376 100644
--- a/src/client/app/common/views/components/poll.vue
+++ b/src/client/app/common/views/components/poll.vue
@@ -4,7 +4,7 @@
 		<li v-for="choice in poll.choices" :key="choice.id" @click="vote(choice.id)" :class="{ voted: choice.voted }" :title="!isVoted ? '%i18n:@vote-to%'.replace('{}', choice.text) : ''">
 			<div class="backdrop" :style="{ 'width': (showResult ? (choice.votes / total * 100) : 0) + '%' }"></div>
 			<span>
-				<template v-if="choice.isVoted">%fa:check%</template>
+				<template v-if="choice.isVoted"><fa icon="check"/></template>
 				<span>{{ choice.text }}</span>
 				<span class="votes" v-if="showResult">({{ '%i18n:@vote-count%'.replace('{}', choice.votes) }})</span>
 			</span>
@@ -100,7 +100,7 @@ export default Vue.extend({
 				transition width 1s ease
 
 			> span
-				> [data-fa]
+				> [data-icon]
 					margin-right 4px
 
 				> .votes
diff --git a/src/client/app/common/views/components/profile-editor.vue b/src/client/app/common/views/components/profile-editor.vue
index 10bdc0b57..4e324b08d 100644
--- a/src/client/app/common/views/components/profile-editor.vue
+++ b/src/client/app/common/views/components/profile-editor.vue
@@ -1,6 +1,6 @@
 <template>
 <ui-card>
-	<div slot="title">%fa:user% %i18n:@title%</div>
+	<div slot="title"><fa icon="user"/> %i18n:@title%</div>
 
 	<section class="fit-top">
 		<ui-form :disabled="saving">
@@ -16,12 +16,12 @@
 
 			<ui-input v-model="location">
 				<span>%i18n:@location%</span>
-				<span slot="prefix">%fa:map-marker-alt%</span>
+				<span slot="prefix"><fa icon="map-marker-alt"/></span>
 			</ui-input>
 
 			<ui-input v-model="birthday" type="date">
 				<span>%i18n:@birthday%</span>
-				<span slot="prefix">%fa:birthday-cake%</span>
+				<span slot="prefix"><fa icon="birthday-cake"/></span>
 			</ui-input>
 
 			<ui-textarea v-model="description" :max="500">
@@ -30,13 +30,13 @@
 
 			<ui-input type="file" @change="onAvatarChange">
 				<span>%i18n:@avatar%</span>
-				<span slot="icon">%fa:image%</span>
+				<span slot="icon"><fa icon="image"/></span>
 				<span slot="text" v-if="avatarUploading">%i18n:@uploading%<mk-ellipsis/></span>
 			</ui-input>
 
 			<ui-input type="file" @change="onBannerChange">
 				<span>%i18n:@banner%</span>
-				<span slot="icon">%fa:image%</span>
+				<span slot="icon"><fa icon="image"/></span>
 				<span slot="text" v-if="bannerUploading">%i18n:@uploading%<mk-ellipsis/></span>
 			</ui-input>
 
diff --git a/src/client/app/common/views/components/signin.vue b/src/client/app/common/views/components/signin.vue
index 0b81daf17..cd24cdd8d 100644
--- a/src/client/app/common/views/components/signin.vue
+++ b/src/client/app/common/views/components/signin.vue
@@ -8,7 +8,7 @@
 	</ui-input>
 	<ui-input v-model="password" type="password" required styl="fill">
 		<span>%i18n:@password%</span>
-		<span slot="prefix">%fa:lock%</span>
+		<span slot="prefix"><fa icon="lock"/></span>
 	</ui-input>
 	<ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required styl="fill"/>
 	<ui-button type="submit" :disabled="signing">{{ signing ? '%i18n:@signing-in%' : '%i18n:@signin%' }}</ui-button>
diff --git a/src/client/app/common/views/components/signup.vue b/src/client/app/common/views/components/signup.vue
index 8e06b1349..bc023b339 100644
--- a/src/client/app/common/views/components/signup.vue
+++ b/src/client/app/common/views/components/signup.vue
@@ -3,36 +3,36 @@
 	<template v-if="meta">
 		<ui-input v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required styl="fill">
 			<span>%i18n:@invitation-code%</span>
-			<span slot="prefix">%fa:id-card-alt%</span>
+			<span slot="prefix"><fa icon="id-card-alt"/></span>
 			<p slot="text" v-html="'%i18n:@invitation-info%'.replace('{}', meta.maintainer.url)"></p>
 		</ui-input>
 		<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @input="onChangeUsername" styl="fill">
 			<span>%i18n:@username%</span>
 			<span slot="prefix">@</span>
 			<span slot="suffix">@{{ host }}</span>
-			<p slot="text" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw% %i18n:@checking%</p>
-			<p slot="text" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw% %i18n:@available%</p>
-			<p slot="text" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@unavailable%</p>
-			<p slot="text" v-if="usernameState == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@error%</p>
-			<p slot="text" v-if="usernameState == 'invalid-format'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@invalid-format%</p>
-			<p slot="text" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-short%</p>
-			<p slot="text" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-long%</p>
+			<p slot="text" v-if="usernameState == 'wait'" style="color:#999"><fa icon="spinner .pulse" fixed-width/> %i18n:@checking%</p>
+			<p slot="text" v-if="usernameState == 'ok'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@available%</p>
+			<p slot="text" v-if="usernameState == 'unavailable'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@unavailable%</p>
+			<p slot="text" v-if="usernameState == 'error'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@error%</p>
+			<p slot="text" v-if="usernameState == 'invalid-format'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@invalid-format%</p>
+			<p slot="text" v-if="usernameState == 'min-range'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@too-short%</p>
+			<p slot="text" v-if="usernameState == 'max-range'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@too-long%</p>
 		</ui-input>
 		<ui-input v-model="password" type="password" :autocomplete="Math.random()" required @input="onChangePassword" :with-password-meter="true" styl="fill">
 			<span>%i18n:@password%</span>
-			<span slot="prefix">%fa:lock%</span>
+			<span slot="prefix"><fa icon="lock"/></span>
 			<div slot="text">
-				<p slot="text" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@weak-password%</p>
-				<p slot="text" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw% %i18n:@normal-password%</p>
-				<p slot="text" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw% %i18n:@strong-password%</p>
+				<p slot="text" v-if="passwordStrength == 'low'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@weak-password%</p>
+				<p slot="text" v-if="passwordStrength == 'medium'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@normal-password%</p>
+				<p slot="text" v-if="passwordStrength == 'high'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@strong-password%</p>
 			</div>
 		</ui-input>
 		<ui-input v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @input="onChangePasswordRetype" styl="fill">
 			<span>%i18n:@password% (%i18n:@retype%)</span>
-			<span slot="prefix">%fa:lock%</span>
+			<span slot="prefix"><fa icon="lock"/></span>
 			<div slot="text">
-				<p slot="text" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw% %i18n:@password-matched%</p>
-				<p slot="text" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@password-not-matched%</p>
+				<p slot="text" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@password-matched%</p>
+				<p slot="text" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@password-not-matched%</p>
 			</div>
 		</ui-input>
 		<div v-if="meta.recaptchaSitekey != null" class="g-recaptcha" :data-sitekey="meta.recaptchaSitekey" style="margin: 16px 0;"></div>
diff --git a/src/client/app/common/views/components/stream-indicator.vue b/src/client/app/common/views/components/stream-indicator.vue
index 12bf78f13..d639261fd 100644
--- a/src/client/app/common/views/components/stream-indicator.vue
+++ b/src/client/app/common/views/components/stream-indicator.vue
@@ -1,15 +1,15 @@
 <template>
 <div class="mk-stream-indicator">
 	<p v-if="stream.state == 'initializing'">
-		%fa:spinner .pulse%
+		<fa icon="spinner .pulse"/>
 		<span>%i18n:@connecting%<mk-ellipsis/></span>
 	</p>
 	<p v-if="stream.state == 'reconnecting'">
-		%fa:spinner .pulse%
+		<fa icon="spinner .pulse"/>
 		<span>%i18n:@reconnecting%<mk-ellipsis/></span>
 	</p>
 	<p v-if="stream.state == 'connected'">
-		%fa:check%
+		<fa icon="check"/>
 		<span>%i18n:@connected%</span>
 	</p>
 </div>
@@ -80,7 +80,7 @@ export default Vue.extend({
 		display block
 		margin 0
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 0.25em
 
 </style>
diff --git a/src/client/app/common/views/components/tag-cloud.vue b/src/client/app/common/views/components/tag-cloud.vue
index 5cc828082..5a1768828 100644
--- a/src/client/app/common/views/components/tag-cloud.vue
+++ b/src/client/app/common/views/components/tag-cloud.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="jtivnzhfwquxpsfidertopbmwmchmnmo">
-	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
-	<p class="empty" v-else-if="tags.length == 0">%fa:exclamation-circle%%i18n:@empty%</p>
+	<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
+	<p class="empty" v-else-if="tags.length == 0"><fa icon="exclamation-circle"/>%i18n:@empty%</p>
 	<div v-else>
 		<vue-word-cloud
 				:words="tags.slice(0, 20).map(x => [x.name, x.count])"
@@ -74,7 +74,7 @@ export default Vue.extend({
 		text-align center
 		color #aaa
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 
 	> div
diff --git a/src/client/app/common/views/components/theme.vue b/src/client/app/common/views/components/theme.vue
index c1c73b97c..d4e8d155e 100644
--- a/src/client/app/common/views/components/theme.vue
+++ b/src/client/app/common/views/components/theme.vue
@@ -25,7 +25,7 @@
 	</label>
 
 	<details class="creator">
-		<summary>%fa:palette% %i18n:@create-a-theme%</summary>
+		<summary><fa icon="palette"/> %i18n:@create-a-theme%</summary>
 		<div>
 			<span>%i18n:@base-theme%:</span>
 			<ui-radio v-model="myThemeBase" value="light">%i18n:@base-theme-light%</ui-radio>
@@ -51,23 +51,23 @@
 			<div style="padding-bottom:8px;">%i18n:@text-color%:</div>
 			<color-picker v-model="myThemeText"/>
 		</div>
-		<ui-button @click="preview()">%fa:eye% %i18n:@preview-created-theme%</ui-button>
-		<ui-button primary @click="gen()">%fa:save R% %i18n:@save-created-theme%</ui-button>
+		<ui-button @click="preview()"><fa icon="eye"/> %i18n:@preview-created-theme%</ui-button>
+		<ui-button primary @click="gen()"><fa :icon="['far', 'save']"/> %i18n:@save-created-theme%</ui-button>
 	</details>
 
 	<details>
-		<summary>%fa:download% %i18n:@install-a-theme%</summary>
-		<ui-button @click="import_()">%fa:file-import% %i18n:@import%</ui-button>
+		<summary><fa icon="download"/> %i18n:@install-a-theme%</summary>
+		<ui-button @click="import_()"><fa icon="file-import"/> %i18n:@import%</ui-button>
 		<input ref="file" type="file" accept=".misskeytheme" style="display:none;" @change="onUpdateImportFile"/>
 		<p>%i18n:@import-by-code%:</p>
 		<ui-textarea v-model="installThemeCode">
 			<span>%i18n:@theme-code%</span>
 		</ui-textarea>
-		<ui-button @click="() => install(this.installThemeCode)">%fa:check% %i18n:@install%</ui-button>
+		<ui-button @click="() => install(this.installThemeCode)"><fa icon="check"/> %i18n:@install%</ui-button>
 	</details>
 
 	<details>
-		<summary>%fa:folder-open% %i18n:@manage-themes%</summary>
+		<summary><fa icon="folder-open"/> %i18n:@manage-themes%</summary>
 		<ui-select v-model="selectedThemeId" placeholder="%i18n:@select-theme%">
 			<optgroup label="%i18n:@builtin-themes%">
 				<option v-for="x in builtinThemes" :value="x.id" :key="x.id">{{ x.name }}</option>
@@ -89,8 +89,8 @@
 			<ui-textarea readonly :value="selectedThemeCode">
 				<span>%i18n:@theme-code%</span>
 			</ui-textarea>
-			<ui-button @click="export_()" link :download="`${selectedTheme.name}.misskeytheme`" ref="export">%fa:box% %i18n:@export%</ui-button>
-			<ui-button @click="uninstall()" v-if="!builtinThemes.some(t => t.id == selectedTheme.id)">%fa:trash-alt R% %i18n:@uninstall%</ui-button>
+			<ui-button @click="export_()" link :download="`${selectedTheme.name}.misskeytheme`" ref="export"><fa icon="box"/> %i18n:@export%</ui-button>
+			<ui-button @click="uninstall()" v-if="!builtinThemes.some(t => t.id == selectedTheme.id)"><fa :icon="['far', 'trash-alt']"/> %i18n:@uninstall%</ui-button>
 		</template>
 	</details>
 </div>
diff --git a/src/client/app/common/views/components/trends.vue b/src/client/app/common/views/components/trends.vue
index 3d36d7449..ea3f854c6 100644
--- a/src/client/app/common/views/components/trends.vue
+++ b/src/client/app/common/views/components/trends.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="csqvmxybqbycalfhkxvyfrgbrdalkaoc">
-	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
-	<p class="empty" v-else-if="stats.length == 0">%fa:exclamation-circle%%i18n:@empty%</p>
+	<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
+	<p class="empty" v-else-if="stats.length == 0"><fa icon="exclamation-circle"/>%i18n:@empty%</p>
 	<!-- トランジションを有効にするとなぜかメモリリークする -->
 	<transition-group v-else tag="div" name="chart">
 		<div v-for="stat in stats" :key="stat.tag">
@@ -58,7 +58,7 @@ export default Vue.extend({
 		color var(--text)
 		opacity 0.7
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 
 	> div
diff --git a/src/client/app/common/views/components/ui/info.vue b/src/client/app/common/views/components/ui/info.vue
index 3d62a3c7a..30fd8cb34 100644
--- a/src/client/app/common/views/components/ui/info.vue
+++ b/src/client/app/common/views/components/ui/info.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="ymxyweixqwsxauxldgpvecjepnwxbylu" :class="{ warn }">
-	<i v-if="warn">%fa:exclamation-triangle%</i>
-	<i v-else>%fa:info-circle%</i>
+	<i v-if="warn"><fa icon="exclamation-triangle"/></i>
+	<i v-else><fa icon="info-circle"/></i>
 	<slot></slot>
 </div>
 </template>
diff --git a/src/client/app/common/views/components/uploader.vue b/src/client/app/common/views/components/uploader.vue
index b812064bb..67ad7ecc9 100644
--- a/src/client/app/common/views/components/uploader.vue
+++ b/src/client/app/common/views/components/uploader.vue
@@ -3,7 +3,7 @@
 	<ol v-if="uploads.length > 0">
 		<li v-for="ctx in uploads" :key="ctx.id">
 			<div class="img" :style="{ backgroundImage: `url(${ ctx.img })` }"></div>
-			<p class="name">%fa:spinner .pulse%{{ ctx.name }}</p>
+			<p class="name"><fa icon="spinner .pulse"/>{{ ctx.name }}</p>
 			<p class="status">
 				<span class="initing" v-if="ctx.progress == undefined">%i18n:@waiting%<mk-ellipsis/></span>
 				<span class="kb" v-if="ctx.progress != undefined">{{ String(Math.floor(ctx.progress.value / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i> / {{ String(Math.floor(ctx.progress.max / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i></span>
@@ -155,7 +155,7 @@ export default Vue.extend({
 				text-overflow ellipsis
 				overflow hidden
 
-				> [data-fa]
+				> [data-icon]
 					margin-right 4px
 
 			> .status
diff --git a/src/client/app/common/views/components/url.vue b/src/client/app/common/views/components/url.vue
index 04a1f3013..8698cb4a0 100644
--- a/src/client/app/common/views/components/url.vue
+++ b/src/client/app/common/views/components/url.vue
@@ -6,7 +6,7 @@
 	<span class="pathname" v-if="pathname != ''">{{ pathname }}</span>
 	<span class="query">{{ query }}</span>
 	<span class="hash">{{ hash }}</span>
-	%fa:external-link-square-alt%
+	<fa icon="external-link-square-alt"/>
 </a>
 </template>
 
@@ -40,7 +40,7 @@ export default Vue.extend({
 <style lang="stylus" scoped>
 .mk-url
 	word-break break-all
-	> [data-fa]
+	> [data-icon]
 		padding-left 2px
 		font-size .9em
 		font-weight 400
diff --git a/src/client/app/common/views/components/visibility-chooser.vue b/src/client/app/common/views/components/visibility-chooser.vue
index 02f33bfbc..62ec9c35e 100644
--- a/src/client/app/common/views/components/visibility-chooser.vue
+++ b/src/client/app/common/views/components/visibility-chooser.vue
@@ -3,34 +3,34 @@
 	<div class="backdrop" ref="backdrop" @click="close"></div>
 	<div class="popover" :class="{ compact }" ref="popover">
 		<div @click="choose('public')" :class="{ active: v == 'public' }">
-			<div>%fa:globe%</div>
+			<div><fa icon="globe"/></div>
 			<div>
 				<span>%i18n:@public%</span>
 			</div>
 		</div>
 		<div @click="choose('home')" :class="{ active: v == 'home' }">
-			<div>%fa:home%</div>
+			<div><fa icon="home"/></div>
 			<div>
 				<span>%i18n:@home%</span>
 				<span>%i18n:@home-desc%</span>
 			</div>
 		</div>
 		<div @click="choose('followers')" :class="{ active: v == 'followers' }">
-			<div>%fa:unlock%</div>
+			<div><fa icon="unlock"/></div>
 			<div>
 				<span>%i18n:@followers%</span>
 				<span>%i18n:@followers-desc%</span>
 			</div>
 		</div>
 		<div @click="choose('specified')" :class="{ active: v == 'specified' }">
-			<div>%fa:envelope%</div>
+			<div><fa icon="envelope"/></div>
 			<div>
 				<span>%i18n:@specified%</span>
 				<span>%i18n:@specified-desc%</span>
 			</div>
 		</div>
 		<div @click="choose('private')" :class="{ active: v == 'private' }">
-			<div>%fa:lock%</div>
+			<div><fa icon="lock"/></div>
 			<div>
 				<span>%i18n:@private%</span>
 			</div>
diff --git a/src/client/app/common/views/pages/follow.vue b/src/client/app/common/views/pages/follow.vue
index 92f24fb53..b800d65d1 100644
--- a/src/client/app/common/views/pages/follow.vue
+++ b/src/client/app/common/views/pages/follow.vue
@@ -19,13 +19,13 @@
 			@click="onClick"
 			:disabled="followWait">
 		<template v-if="!followWait">
-			<template v-if="user.hasPendingFollowRequestFromYou && user.isLocked">%fa:hourglass-half% %i18n:@request-pending%</template>
-			<template v-else-if="user.hasPendingFollowRequestFromYou && !user.isLocked">%fa:hourglass-start% %i18n:@follow-processing%</template>
-			<template v-else-if="user.isFollowing">%fa:minus% %i18n:@following%</template>
-			<template v-else-if="!user.isFollowing && user.isLocked">%fa:plus% %i18n:@follow-request%</template>
-			<template v-else-if="!user.isFollowing && !user.isLocked">%fa:plus% %i18n:@follow%</template>
+			<template v-if="user.hasPendingFollowRequestFromYou && user.isLocked"><fa icon="hourglass-half"/> %i18n:@request-pending%</template>
+			<template v-else-if="user.hasPendingFollowRequestFromYou && !user.isLocked"><fa icon="hourglass-start"/> %i18n:@follow-processing%</template>
+			<template v-else-if="user.isFollowing"><fa icon="minus"/> %i18n:@following%</template>
+			<template v-else-if="!user.isFollowing && user.isLocked"><fa icon="plus"/> %i18n:@follow-request%</template>
+			<template v-else-if="!user.isFollowing && !user.isLocked"><fa icon="plus"/> %i18n:@follow%</template>
 		</template>
-		<template v-else>%fa:spinner .pulse .fw%</template>
+		<template v-else><fa icon="spinner .pulse" fixed-width/></template>
 	</button>
 </div>
 </template>
diff --git a/src/client/app/common/views/widgets/donation.vue b/src/client/app/common/views/widgets/donation.vue
index b025b41e7..4ef1557f9 100644
--- a/src/client/app/common/views/widgets/donation.vue
+++ b/src/client/app/common/views/widgets/donation.vue
@@ -2,7 +2,7 @@
 <div>
 	<mk-widget-container :show-header="false">
 		<article class="dolfvtibguprpxxhfndqaosjitixjohx">
-			<h1>%fa:heart%%i18n:@title%</h1>
+			<h1><fa icon="heart"/>%i18n:@title%</h1>
 			<p v-if="meta">
 				{{ '%i18n:@text%'.substr(0, '%i18n:@text%'.indexOf('{')) }}
 				<a :href="meta.maintainer.url">{{ meta.maintainer.name }}</a>
@@ -41,7 +41,7 @@ export default define({
 		margin 0 0 5px 0
 		font-size 1em
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 0.25em
 
 	> p
diff --git a/src/client/app/common/views/widgets/hashtags.vue b/src/client/app/common/views/widgets/hashtags.vue
index 0cb6b2df1..656c68317 100644
--- a/src/client/app/common/views/widgets/hashtags.vue
+++ b/src/client/app/common/views/widgets/hashtags.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mkw-hashtags">
 	<mk-widget-container :show-header="!props.compact">
-		<template slot="header">%fa:hashtag%%i18n:@title%</template>
+		<template slot="header"><fa icon="hashtag"/>%i18n:@title%</template>
 
 		<div class="mkw-hashtags--body" :data-mobile="platform == 'mobile'">
 			<mk-trends/>
diff --git a/src/client/app/common/views/widgets/memo.vue b/src/client/app/common/views/widgets/memo.vue
index be8b18a4e..07d0c5834 100644
--- a/src/client/app/common/views/widgets/memo.vue
+++ b/src/client/app/common/views/widgets/memo.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mkw-memo">
 	<mk-widget-container :show-header="!props.compact">
-		<template slot="header">%fa:R sticky-note%%i18n:@title%</template>
+		<template slot="header"><fa :icon="['far', 'sticky-note']"/>%i18n:@title%</template>
 
 		<div class="mkw-memo--body">
 			<textarea v-model="text" placeholder="%i18n:@memo%" @input="onChange"></textarea>
diff --git a/src/client/app/common/views/widgets/photo-stream.vue b/src/client/app/common/views/widgets/photo-stream.vue
index fd711b276..9c6ce129b 100644
--- a/src/client/app/common/views/widgets/photo-stream.vue
+++ b/src/client/app/common/views/widgets/photo-stream.vue
@@ -1,9 +1,9 @@
 <template>
 <div class="mkw-photo-stream" :class="$style.root" :data-melt="props.design == 2">
 	<mk-widget-container :show-header="props.design == 0" :naked="props.design == 2">
-		<template slot="header">%fa:camera%%i18n:@title%</template>
+		<template slot="header"><fa icon="camera"/>%i18n:@title%</template>
 
-		<p :class="$style.fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
+		<p :class="$style.fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
 		<div :class="$style.stream" v-if="!fetching && images.length > 0">
 			<div v-for="image in images" :class="$style.img" :style="`background-image: url(${image.thumbnailUrl || image.url})`"></div>
 		</div>
@@ -94,7 +94,7 @@ export default define({
 	text-align center
 	color #aaa
 
-	> [data-fa]
+	> [data-icon]
 		margin-right 4px
 
 </style>
diff --git a/src/client/app/common/views/widgets/posts-monitor.vue b/src/client/app/common/views/widgets/posts-monitor.vue
index c62533d1e..4527489f5 100644
--- a/src/client/app/common/views/widgets/posts-monitor.vue
+++ b/src/client/app/common/views/widgets/posts-monitor.vue
@@ -1,8 +1,8 @@
 <template>
 <div class="mkw-posts-monitor">
 	<mk-widget-container :show-header="props.design == 0" :naked="props.design == 2">
-		<template slot="header">%fa:chart-line%%i18n:@title%</template>
-		<button slot="func" @click="toggle" title="%i18n:@toggle%">%fa:sort%</button>
+		<template slot="header"><fa icon="chart-line"/>%i18n:@title%</template>
+		<button slot="func" @click="toggle" title="%i18n:@toggle%"><fa icon="sort"/></button>
 
 		<div class="qpdmibaztplkylerhdbllwcokyrfxeyj" :class="{ dual: props.view == 0 }">
 			<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" v-show="props.view != 2">
diff --git a/src/client/app/common/views/widgets/rss.vue b/src/client/app/common/views/widgets/rss.vue
index 68ab8e3a5..2fc97c804 100644
--- a/src/client/app/common/views/widgets/rss.vue
+++ b/src/client/app/common/views/widgets/rss.vue
@@ -1,11 +1,11 @@
 <template>
 <div class="mkw-rss">
 	<mk-widget-container :show-header="!props.compact">
-		<template slot="header">%fa:rss-square%RSS</template>
-		<button slot="func" title="設定" @click="setting">%fa:cog%</button>
+		<template slot="header"><fa icon="rss-square"/>RSS</template>
+		<button slot="func" title="設定" @click="setting"><fa icon="cog"/></button>
 
 		<div class="mkw-rss--body" :data-mobile="platform == 'mobile'">
-			<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
+			<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
 			<div class="feed" v-else>
 				<a v-for="item in items" :href="item.link" target="_blank">{{ item.title }}</a>
 			</div>
@@ -85,7 +85,7 @@ export default define({
 			text-align center
 			color #aaa
 
-			> [data-fa]
+			> [data-icon]
 				margin-right 4px
 
 		&[data-mobile]
diff --git a/src/client/app/common/views/widgets/server.cpu.vue b/src/client/app/common/views/widgets/server.cpu.vue
index 2034aee0e..986577c51 100644
--- a/src/client/app/common/views/widgets/server.cpu.vue
+++ b/src/client/app/common/views/widgets/server.cpu.vue
@@ -2,7 +2,7 @@
 <div class="cpu">
 	<x-pie class="pie" :value="usage"/>
 	<div>
-		<p>%fa:microchip%CPU</p>
+		<p><fa icon="microchip"/>CPU</p>
 		<p>{{ meta.cpu.cores }} Cores</p>
 		<p>{{ meta.cpu.model }}</p>
 	</div>
@@ -57,7 +57,7 @@ export default Vue.extend({
 			&:first-child
 				font-weight bold
 
-				> [data-fa]
+				> [data-icon]
 					margin-right 4px
 
 	&:after
diff --git a/src/client/app/common/views/widgets/server.disk.vue b/src/client/app/common/views/widgets/server.disk.vue
index 667576ab7..039c4f5c2 100644
--- a/src/client/app/common/views/widgets/server.disk.vue
+++ b/src/client/app/common/views/widgets/server.disk.vue
@@ -2,7 +2,7 @@
 <div class="disk">
 	<x-pie class="pie" :value="usage"/>
 	<div>
-		<p>%fa:R hdd%Storage</p>
+		<p><fa :icon="['far', 'hdd']"/>Storage</p>
 		<p>Total: {{ total | bytes(1) }}</p>
 		<p>Free: {{ available | bytes(1) }}</p>
 		<p>Used: {{ used | bytes(1) }}</p>
@@ -65,7 +65,7 @@ export default Vue.extend({
 			&:first-child
 				font-weight bold
 
-				> [data-fa]
+				> [data-icon]
 					margin-right 4px
 
 	&:after
diff --git a/src/client/app/common/views/widgets/server.memory.vue b/src/client/app/common/views/widgets/server.memory.vue
index 9e12884cf..d7ad04b08 100644
--- a/src/client/app/common/views/widgets/server.memory.vue
+++ b/src/client/app/common/views/widgets/server.memory.vue
@@ -2,7 +2,7 @@
 <div class="memory">
 	<x-pie class="pie" :value="usage"/>
 	<div>
-		<p>%fa:flask%Memory</p>
+		<p><fa icon="flask"/>Memory</p>
 		<p>Total: {{ total | bytes(1) }}</p>
 		<p>Used: {{ used | bytes(1) }}</p>
 		<p>Free: {{ free | bytes(1) }}</p>
@@ -65,7 +65,7 @@ export default Vue.extend({
 			&:first-child
 				font-weight bold
 
-				> [data-fa]
+				> [data-icon]
 					margin-right 4px
 
 	&:after
diff --git a/src/client/app/common/views/widgets/server.vue b/src/client/app/common/views/widgets/server.vue
index 62d75e2bf..18c2af1e4 100644
--- a/src/client/app/common/views/widgets/server.vue
+++ b/src/client/app/common/views/widgets/server.vue
@@ -1,10 +1,10 @@
 <template>
 <div class="mkw-server">
 	<mk-widget-container :show-header="props.design == 0" :naked="props.design == 2">
-		<template slot="header">%fa:server%%i18n:@title%</template>
-		<button slot="func" @click="toggle" title="%i18n:@toggle%">%fa:sort%</button>
+		<template slot="header"><fa icon="server"/>%i18n:@title%</template>
+		<button slot="func" @click="toggle" title="%i18n:@toggle%"><fa icon="sort"/></button>
 
-		<p :class="$style.fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
+		<p :class="$style.fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
 		<template v-if="!fetching">
 			<x-cpu-memory v-show="props.view == 0" :connection="connection"/>
 			<x-cpu v-show="props.view == 1" :connection="connection" :meta="meta"/>
@@ -87,7 +87,7 @@ export default define({
 	text-align center
 	color #aaa
 
-	> [data-fa]
+	> [data-icon]
 		margin-right 4px
 
 </style>
diff --git a/src/client/app/common/views/widgets/tips.vue b/src/client/app/common/views/widgets/tips.vue
index 7bb11d465..3ed654880 100644
--- a/src/client/app/common/views/widgets/tips.vue
+++ b/src/client/app/common/views/widgets/tips.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="mkw-tips">
-	<p ref="tip">%fa:R lightbulb%<span v-html="tip"></span></p>
+	<p ref="tip"><fa :icon="['far', 'lightbulb']"/><span v-html="tip"></span></p>
 </div>
 </template>
 
@@ -88,7 +88,7 @@ export default define({
 		font-size 0.7em
 		color #999
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 
 		kbd
diff --git a/src/client/app/desktop/views/components/activity.vue b/src/client/app/desktop/views/components/activity.vue
index e9ed532a3..941fb5916 100644
--- a/src/client/app/desktop/views/components/activity.vue
+++ b/src/client/app/desktop/views/components/activity.vue
@@ -1,10 +1,10 @@
 <template>
 <div class="mk-activity">
 	<mk-widget-container :show-header="design == 0" :naked="design == 2">
-		<template slot="header">%fa:chart-bar%%i18n:@title%</template>
-		<button slot="func" title="%i18n:@toggle%" @click="toggle">%fa:sort%</button>
+		<template slot="header"><fa icon="chart-bar"/>%i18n:@title%</template>
+		<button slot="func" title="%i18n:@toggle%" @click="toggle"><fa icon="sort"/></button>
 
-		<p :class="$style.fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
+		<p :class="$style.fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
 		<template v-else>
 			<x-calendar v-show="view == 0" :data="[].concat(activity)"/>
 			<x-chart v-show="view == 1" :data="[].concat(activity)"/>
@@ -78,7 +78,7 @@ export default Vue.extend({
 	text-align center
 	color #aaa
 
-	> [data-fa]
+	> [data-icon]
 		margin-right 4px
 
 </style>
diff --git a/src/client/app/desktop/views/components/calendar.vue b/src/client/app/desktop/views/components/calendar.vue
index e2f1329b3..7eb5e5ad1 100644
--- a/src/client/app/desktop/views/components/calendar.vue
+++ b/src/client/app/desktop/views/components/calendar.vue
@@ -1,9 +1,9 @@
 <template>
 <div class="mk-calendar" :data-melt="design == 4 || design == 5">
 	<template v-if="design == 0 || design == 1">
-		<button @click="prev" title="%i18n:@prev%">%fa:chevron-circle-left%</button>
+		<button @click="prev" title="%i18n:@prev%"><fa icon="chevron-circle-left"/></button>
 		<p class="title">{{ '%i18n:@title%'.replace('{1}', year).replace('{2}', month) }}</p>
-		<button @click="next" title="%i18n:@next%">%fa:chevron-circle-right%</button>
+		<button @click="next" title="%i18n:@next%"><fa icon="chevron-circle-right"/></button>
 	</template>
 
 	<div class="calendar">
@@ -151,7 +151,7 @@ export default Vue.extend({
 		background var(--faceHeader)
 		box-shadow 0 1px rgba(#000, 0.07)
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 
 	> button
diff --git a/src/client/app/desktop/views/components/choose-file-from-drive-window.vue b/src/client/app/desktop/views/components/choose-file-from-drive-window.vue
index 806f7f5c3..268ace74d 100644
--- a/src/client/app/desktop/views/components/choose-file-from-drive-window.vue
+++ b/src/client/app/desktop/views/components/choose-file-from-drive-window.vue
@@ -13,7 +13,7 @@
 		@change-selection="onChangeSelection"
 	/>
 	<div :class="$style.footer">
-		<button :class="$style.upload" title="%i18n:@upload%" @click="upload">%fa:upload%</button>
+		<button :class="$style.upload" title="%i18n:@upload%" @click="upload"><fa icon="upload"/></button>
 		<button :class="$style.cancel" @click="cancel">%i18n:@cancel%</button>
 		<button :class="$style.ok" :disabled="multiple && files.length == 0" @click="ok">%i18n:@ok%</button>
 	</div>
@@ -28,7 +28,7 @@ export default Vue.extend({
 			default: false
 		},
 		title: {
-			default: '%fa:R file%%i18n:@choose-prompt%'
+			default: '<fa :icon="['far', 'file']"/>%i18n:@choose-prompt%'
 		}
 	},
 	data() {
@@ -62,7 +62,7 @@ export default Vue.extend({
 
 
 .title
-	> [data-fa]
+	> [data-icon]
 		margin-right 4px
 
 .count
diff --git a/src/client/app/desktop/views/components/choose-folder-from-drive-window.vue b/src/client/app/desktop/views/components/choose-folder-from-drive-window.vue
index b970218e5..eeeaffe7e 100644
--- a/src/client/app/desktop/views/components/choose-folder-from-drive-window.vue
+++ b/src/client/app/desktop/views/components/choose-folder-from-drive-window.vue
@@ -21,7 +21,7 @@ import Vue from 'vue';
 export default Vue.extend({
 	props: {
 		title: {
-			default: '%fa:R folder%%i18n:@choose-prompt%'
+			default: '<fa :icon="['far', 'folder']"/>%i18n:@choose-prompt%'
 		}
 	},
 	methods: {
@@ -40,7 +40,7 @@ export default Vue.extend({
 
 
 .title
-	> [data-fa]
+	> [data-icon]
 		margin-right 4px
 
 .browser
diff --git a/src/client/app/desktop/views/components/context-menu.menu.vue b/src/client/app/desktop/views/components/context-menu.menu.vue
index 9e4541a75..fae7811ea 100644
--- a/src/client/app/desktop/views/components/context-menu.menu.vue
+++ b/src/client/app/desktop/views/components/context-menu.menu.vue
@@ -3,13 +3,13 @@
 	<li v-for="(item, i) in menu" :class="item ? item.type : item === null ? 'divider' : null">
 		<template v-if="item">
 			<template v-if="item.type == null || item.type == 'item'">
-				<p @click="click(item)"><span :class="$style.icon" v-if="item.icon" v-html="item.icon"></span>{{ item.text }}</p>
+				<p @click="click(item)"><i v-if="item.icon" :class="$style.icon"><fa :icon="item.icon"/></i>{{ item.text }}</p>
 			</template>
 			<template v-else-if="item.type == 'link'">
-				<a :href="item.href" :target="item.target" @click="click(item)"><span :class="$style.icon" v-if="item.icon" v-html="item.icon"></span>{{ item.text }}</a>
+				<a :href="item.href" :target="item.target" @click="click(item)"><i v-if="item.icon" :class="$style.icon"><fa :icon="item.icon"/></i>{{ item.text }}</a>
 			</template>
 			<template v-else-if="item.type == 'nest'">
-				<p><span :class="$style.icon" v-if="item.icon" v-html="item.icon"></span>{{ item.text }}...<span class="caret">%fa:caret-right%</span></p>
+				<p><i v-if="item.icon" :class="$style.icon"><fa :icon="item.icon"/></i>{{ item.text }}...<span class="caret"><fa icon="caret-right"/></span></p>
 				<me-nu :menu="item.menu" @x="click"/>
 			</template>
 		</template>
@@ -113,9 +113,9 @@ export default Vue.extend({
 
 <style lang="stylus" module>
 .icon
-	> *
-		width 28px
-		margin-left -28px
-		text-align center
+	display inline-block
+	width 28px
+	margin-left -28px
+	text-align center
 </style>
 
diff --git a/src/client/app/desktop/views/components/crop-window.vue b/src/client/app/desktop/views/components/crop-window.vue
index 629c3b013..8aeb90b53 100644
--- a/src/client/app/desktop/views/components/crop-window.vue
+++ b/src/client/app/desktop/views/components/crop-window.vue
@@ -1,6 +1,6 @@
 <template>
 	<mk-window ref="window" is-modal width="800px" :can-close="false">
-		<span slot="header">%fa:crop%{{ title }}</span>
+		<span slot="header"><fa icon="crop"/>{{ title }}</span>
 		<div class="body">
 			<vue-cropper ref="cropper"
 				:src="image.url"
@@ -64,7 +64,7 @@ export default Vue.extend({
 
 
 .header
-	> [data-fa]
+	> [data-icon]
 		margin-right 4px
 
 .img
diff --git a/src/client/app/desktop/views/components/dialog.vue b/src/client/app/desktop/views/components/dialog.vue
index baa6f911f..2664105bd 100644
--- a/src/client/app/desktop/views/components/dialog.vue
+++ b/src/client/app/desktop/views/components/dialog.vue
@@ -91,8 +91,6 @@ export default Vue.extend({
 </script>
 
 <style lang="stylus" scoped>
-
-
 .mk-dialog
 	> .bg
 		display block
diff --git a/src/client/app/desktop/views/components/drive-window.vue b/src/client/app/desktop/views/components/drive-window.vue
index aa3c2b6b3..5f9818969 100644
--- a/src/client/app/desktop/views/components/drive-window.vue
+++ b/src/client/app/desktop/views/components/drive-window.vue
@@ -2,7 +2,7 @@
 <mk-window ref="window" @closed="destroyDom" width="800px" height="500px" :popout-url="popout">
 	<template slot="header">
 		<p v-if="usage" :class="$style.info"><b>{{ usage.toFixed(1) }}%</b> %i18n:@used%</p>
-		<span :class="$style.title">%fa:cloud%%i18n:common.drive%</span>
+		<span :class="$style.title"><fa icon="cloud"/>%i18n:common.drive%</span>
 	</template>
 	<mk-drive :class="$style.browser" multiple :init-folder="folder" ref="browser"/>
 </mk-window>
@@ -39,7 +39,7 @@ export default Vue.extend({
 
 <style lang="stylus" module>
 .title
-	> [data-fa]
+	> [data-icon]
 		margin-right 4px
 
 .info
diff --git a/src/client/app/desktop/views/components/drive.file.vue b/src/client/app/desktop/views/components/drive.file.vue
index d7e24cfe7..90a57b148 100644
--- a/src/client/app/desktop/views/components/drive.file.vue
+++ b/src/client/app/desktop/views/components/drive.file.vue
@@ -71,27 +71,27 @@ export default Vue.extend({
 			contextmenu((this as any).os)(e, [{
 				type: 'item',
 				text: '%i18n:@contextmenu.rename%',
-				icon: '%fa:i-cursor%',
+				icon: 'i-cursor',
 				action: this.rename
 			}, {
 				type: 'item',
 				text: this.file.isSensitive ? '%i18n:@contextmenu.unmark-as-sensitive%' : '%i18n:@contextmenu.mark-as-sensitive%',
-				icon: this.file.isSensitive ? '%fa:R eye%' : '%fa:R eye-slash%',
+				icon: this.file.isSensitive ? ['far', 'eye'] : ['far', 'eye-slash'],
 				action: this.toggleSensitive
 			}, null, {
 				type: 'item',
 				text: '%i18n:@contextmenu.copy-url%',
-				icon: '%fa:link%',
+				icon: 'link',
 				action: this.copyUrl
 			}, {
 				type: 'link',
 				href: `${this.file.url}?download`,
 				text: '%i18n:@contextmenu.download%',
-				icon: '%fa:download%',
+				icon: 'download',
 			}, null, {
 				type: 'item',
 				text: '%i18n:common.delete%',
-				icon: '%fa:R trash-alt%',
+				icon: ['far', 'trash-alt'],
 				action: this.deleteFile
 			}, null, {
 				type: 'nest',
@@ -170,7 +170,7 @@ export default Vue.extend({
 		copyUrl() {
 			copyToClipboard(this.file.url);
 			(this as any).apis.dialog({
-				title: '%fa:check%%i18n:@contextmenu.copied%',
+				title: '<fa icon="check"/>%i18n:@contextmenu.copied%',
 				text: '%i18n:@contextmenu.copied-url-to-clipboard%',
 				actions: [{
 					text: '%i18n:common.ok%'
diff --git a/src/client/app/desktop/views/components/drive.folder.vue b/src/client/app/desktop/views/components/drive.folder.vue
index 0bf2b7136..6862e151d 100644
--- a/src/client/app/desktop/views/components/drive.folder.vue
+++ b/src/client/app/desktop/views/components/drive.folder.vue
@@ -16,8 +16,8 @@
 	:title="title"
 >
 	<p class="name">
-		<template v-if="hover">%fa:R folder-open .fw%</template>
-		<template v-if="!hover">%fa:R folder .fw%</template>
+		<template v-if="hover"><fa :icon="['far', 'folder-open']" fixed-width/></template>
+		<template v-if="!hover"><fa :icon="['far', 'folder']" fixed-width/></template>
 		{{ folder.name }}
 	</p>
 </div>
@@ -55,22 +55,22 @@ export default Vue.extend({
 			contextmenu((this as any).os)(e, [{
 				type: 'item',
 				text: '%i18n:@contextmenu.move-to-this-folder%',
-				icon: '%fa:arrow-right%',
+				icon: 'arrow-right',
 				action: this.go
 			}, {
 				type: 'item',
 				text: '%i18n:@contextmenu.show-in-new-window%',
-				icon: '%fa:R window-restore%',
+				icon: ['far', 'window-restore'],
 				action: this.newWindow
 			}, null, {
 				type: 'item',
 				text: '%i18n:@contextmenu.rename%',
-				icon: '%fa:i-cursor%',
+				icon: 'i-cursor',
 				action: this.rename
 			}, null, {
 				type: 'item',
 				text: '%i18n:common.delete%',
-				icon: '%fa:R trash-alt%',
+				icon: ['far', 'trash-alt'],
 				action: this.deleteFolder
 			}], {
 					closed: () => {
@@ -155,7 +155,7 @@ export default Vue.extend({
 					switch (err) {
 						case 'detected-circular-definition':
 							(this as any).apis.dialog({
-								title: '%fa:exclamation-triangle%%i18n:@unable-to-process%',
+								title: '<fa icon="exclamation-triangle"/>%i18n:@unable-to-process%',
 								text: '%i18n:@circular-reference-detected%',
 								actions: [{
 									text: '%i18n:common.ok%'
@@ -255,7 +255,7 @@ export default Vue.extend({
 		font-size 0.9em
 		color var(--desktopDriveFolderFg)
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 			margin-left 2px
 			text-align left
diff --git a/src/client/app/desktop/views/components/drive.nav-folder.vue b/src/client/app/desktop/views/components/drive.nav-folder.vue
index 4c20e139a..b750a6e5e 100644
--- a/src/client/app/desktop/views/components/drive.nav-folder.vue
+++ b/src/client/app/desktop/views/components/drive.nav-folder.vue
@@ -7,7 +7,7 @@
 	@dragleave="onDragleave"
 	@drop.stop="onDrop"
 >
-	<template v-if="folder == null">%fa:cloud%</template>
+	<i v-if="folder == null" class="cloud"><fa icon="cloud"/></i>
 	<span>{{ folder == null ? '%i18n:common.drive%' : folder.name }}</span>
 </div>
 </template>
@@ -110,7 +110,7 @@ export default Vue.extend({
 	&[data-draghover]
 		background #eee
 
-	[data-fa].cloud
+	i.cloud
 		margin-right 4px
 
 </style>
diff --git a/src/client/app/desktop/views/components/drive.vue b/src/client/app/desktop/views/components/drive.vue
index 4d83a49ce..20861f72b 100644
--- a/src/client/app/desktop/views/components/drive.vue
+++ b/src/client/app/desktop/views/components/drive.vue
@@ -4,10 +4,10 @@
 		<div class="path" @contextmenu.prevent.stop="() => {}">
 			<x-nav-folder :class="{ current: folder == null }"/>
 			<template v-for="folder in hierarchyFolders">
-				<span class="separator">%fa:angle-right%</span>
+				<span class="separator"><fa icon="angle-right"/></span>
 				<x-nav-folder :folder="folder" :key="folder.id"/>
 			</template>
-			<span class="separator" v-if="folder != null">%fa:angle-right%</span>
+			<span class="separator" v-if="folder != null"><fa icon="angle-right"/></span>
 			<span class="folder current" v-if="folder != null">{{ folder.name }}</span>
 		</div>
 		<!--
@@ -138,17 +138,17 @@ export default Vue.extend({
 			contextmenu((this as any).os)(e, [{
 				type: 'item',
 				text: '%i18n:@contextmenu.create-folder%',
-				icon: '%fa:R folder%',
+				icon: ['far', 'folder'],
 				action: this.createFolder
 			}, {
 				type: 'item',
 				text: '%i18n:@contextmenu.upload%',
-				icon: '%fa:upload%',
+				icon: 'upload',
 				action: this.selectLocalFile
 			}, {
 				type: 'item',
 				text: '%i18n:@contextmenu.url-upload%',
-				icon: '%fa:cloud-upload-alt%',
+				icon: 'cloud-upload-alt',
 				action: this.urlUpload
 			}]);
 		},
@@ -313,7 +313,7 @@ export default Vue.extend({
 					switch (err) {
 						case 'detected-circular-definition':
 							(this as any).apis.dialog({
-								title: '%fa:exclamation-triangle%%i18n:@unable-to-process%',
+								title: '<fa icon="exclamation-triangle"/>%i18n:@unable-to-process%',
 								text: '%i18n:@circular-reference-detected%',
 								actions: [{
 									text: '%i18n:common.ok%'
@@ -343,7 +343,7 @@ export default Vue.extend({
 				});
 
 				(this as any).apis.dialog({
-					title: '%fa:check%%i18n:@url-upload-requested%',
+					title: '<fa icon="check"/>%i18n:@url-upload-requested%',
 					text: '%i18n:@may-take-time%',
 					actions: [{
 						text: '%i18n:common.ok%'
@@ -613,9 +613,6 @@ export default Vue.extend({
 				line-height 38px
 				cursor pointer
 
-				i
-					margin-right 4px
-
 				*
 					pointer-events none
 
@@ -635,7 +632,7 @@ export default Vue.extend({
 					opacity 0.5
 					cursor default
 
-					> [data-fa]
+					> [data-icon]
 						margin 0
 
 		> .search
diff --git a/src/client/app/desktop/views/components/follow-button.vue b/src/client/app/desktop/views/components/follow-button.vue
index 11291a2f1..7adda3650 100644
--- a/src/client/app/desktop/views/components/follow-button.vue
+++ b/src/client/app/desktop/views/components/follow-button.vue
@@ -5,13 +5,13 @@
 	:disabled="wait"
 >
 	<template v-if="!wait">
-		<template v-if="u.hasPendingFollowRequestFromYou && u.isLocked">%fa:hourglass-half%<template v-if="size == 'big'"> %i18n:@request-pending%</template></template>
-		<template v-else-if="u.hasPendingFollowRequestFromYou && !u.isLocked">%fa:hourglass-start%<template v-if="size == 'big'"> %i18n:@follow-processing%</template></template>
-		<template v-else-if="u.isFollowing">%fa:minus%<template v-if="size == 'big'"> %i18n:@following%</template></template>
-		<template v-else-if="!u.isFollowing && u.isLocked">%fa:plus%<template v-if="size == 'big'"> %i18n:@follow-request%</template></template>
-		<template v-else-if="!u.isFollowing && !u.isLocked">%fa:plus%<template v-if="size == 'big'"> %i18n:@follow%</template></template>
+		<template v-if="u.hasPendingFollowRequestFromYou && u.isLocked"><fa icon="hourglass-half"/><template v-if="size == 'big'"> %i18n:@request-pending%</template></template>
+		<template v-else-if="u.hasPendingFollowRequestFromYou && !u.isLocked"><fa icon="hourglass-start"/><template v-if="size == 'big'"> %i18n:@follow-processing%</template></template>
+		<template v-else-if="u.isFollowing"><fa icon="minus"/><template v-if="size == 'big'"> %i18n:@following%</template></template>
+		<template v-else-if="!u.isFollowing && u.isLocked"><fa icon="plus"/><template v-if="size == 'big'"> %i18n:@follow-request%</template></template>
+		<template v-else-if="!u.isFollowing && !u.isLocked"><fa icon="plus"/><template v-if="size == 'big'"> %i18n:@follow%</template></template>
 	</template>
-	<template v-else>%fa:spinner .pulse .fw%</template>
+	<template v-else><fa icon="spinner .pulse" fixed-width/></template>
 </button>
 </template>
 
diff --git a/src/client/app/desktop/views/components/friends-maker.vue b/src/client/app/desktop/views/components/friends-maker.vue
index d64890fdb..8b4344ad6 100644
--- a/src/client/app/desktop/views/components/friends-maker.vue
+++ b/src/client/app/desktop/views/components/friends-maker.vue
@@ -11,9 +11,9 @@
 		</div>
 	</div>
 	<p class="empty" v-if="!fetching && users.length == 0">%i18n:@empty%</p>
-	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@fetching%<mk-ellipsis/></p>
+	<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:@fetching%<mk-ellipsis/></p>
 	<a class="refresh" @click="refresh">%i18n:@refresh%</a>
-	<button class="close" @click="destroyDom()" title="%i18n:@close%">%fa:times%</button>
+	<button class="close" @click="destroyDom()" title="%i18n:@close%"><fa icon="times"/></button>
 </div>
 </template>
 
@@ -124,7 +124,7 @@ export default Vue.extend({
 		text-align center
 		color #aaa
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 
 	> .refresh
@@ -155,7 +155,7 @@ export default Vue.extend({
 		&:active
 			color #222
 
-		> [data-fa]
+		> [data-icon]
 			padding 14px
 
 </style>
diff --git a/src/client/app/desktop/views/components/game-window.vue b/src/client/app/desktop/views/components/game-window.vue
index 594eae58f..10e974d42 100644
--- a/src/client/app/desktop/views/components/game-window.vue
+++ b/src/client/app/desktop/views/components/game-window.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-window ref="window" width="500px" height="560px" :popout-url="popout" @closed="destroyDom">
-	<span slot="header" :class="$style.header">%fa:gamepad%%i18n:@game%</span>
+	<span slot="header" :class="$style.header"><fa icon="gamepad"/>%i18n:@game%</span>
 	<mk-reversi :class="$style.content" @gamed="g => game = g"/>
 </mk-window>
 </template>
@@ -27,7 +27,7 @@ export default Vue.extend({
 
 <style lang="stylus" module>
 .header
-	> [data-fa]
+	> [data-icon]
 		margin-right 4px
 
 .content
diff --git a/src/client/app/desktop/views/components/home.vue b/src/client/app/desktop/views/components/home.vue
index 42e936edd..b3bebd262 100644
--- a/src/client/app/desktop/views/components/home.vue
+++ b/src/client/app/desktop/views/components/home.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mk-home" :data-customize="customize">
 	<div class="customize" v-if="customize">
-		<router-link to="/">%fa:check%%i18n:@done%</router-link>
+		<router-link to="/"><fa icon="check"/>%i18n:@done%</router-link>
 		<div>
 			<div class="adder">
 				<p>%i18n:@add-widget%</p>
@@ -185,7 +185,7 @@ export default Vue.extend({
 	methods: {
 		hint() {
 			(this as any).apis.dialog({
-				title: '%fa:info-circle%%i18n:common.customization-tips.title%',
+				title: '<fa icon="info-circle"/>%i18n:common.customization-tips.title%',
 				text: '<p>%i18n:common.customization-tips.paragraph1%</p>' +
 					'<p>%i18n:common.customization-tips.paragraph2%</p>' +
 					'<p>%i18n:common.customization-tips.paragraph3%</p>' +
@@ -299,7 +299,7 @@ export default Vue.extend({
 				background var(--primaryDarken10)
 				transition background 0s ease
 
-			> [data-fa]
+			> [data-icon]
 				margin-right 8px
 
 		> div
diff --git a/src/client/app/desktop/views/components/input-dialog.vue b/src/client/app/desktop/views/components/input-dialog.vue
index 976e897fe..60f672c93 100644
--- a/src/client/app/desktop/views/components/input-dialog.vue
+++ b/src/client/app/desktop/views/components/input-dialog.vue
@@ -1,7 +1,7 @@
 <template>
 <mk-window ref="window" is-modal width="500px" @before-close="beforeClose" @closed="destroyDom">
 	<span slot="header" :class="$style.header">
-		%fa:i-cursor%{{ title }}
+		<fa icon="i-cursor"/>{{ title }}
 	</span>
 
 	<div :class="$style.body">
@@ -76,10 +76,8 @@ export default Vue.extend({
 
 
 <style lang="stylus" module>
-
-
 .header
-	> [data-fa]
+	> [data-icon]
 		margin-right 4px
 
 .body
diff --git a/src/client/app/desktop/views/components/media-image.vue b/src/client/app/desktop/views/components/media-image.vue
index f9ab188ca..9e1a29333 100644
--- a/src/client/app/desktop/views/components/media-image.vue
+++ b/src/client/app/desktop/views/components/media-image.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="ldwbgwstjsdgcjruamauqdrffetqudry" v-if="image.isSensitive && hide && !$store.state.device.alwaysShowNsfw" @click="hide = false">
 	<div>
-		<b>%fa:exclamation-triangle% %i18n:@sensitive%</b>
+		<b><fa icon="exclamation-triangle"/> %i18n:@sensitive%</b>
 		<span>%i18n:@click-to-show%</span>
 	</div>
 </div>
diff --git a/src/client/app/desktop/views/components/media-video.vue b/src/client/app/desktop/views/components/media-video.vue
index 7859a5925..956562148 100644
--- a/src/client/app/desktop/views/components/media-video.vue
+++ b/src/client/app/desktop/views/components/media-video.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="uofhebxjdgksfmltszlxurtjnjjsvioh" v-if="video.isSensitive && hide" @click="hide = false">
 	<div>
-		<b>%fa:exclamation-triangle% %i18n:@sensitive%</b>
+		<b><fa icon="exclamation-triangle"/> %i18n:@sensitive%</b>
 		<span>%i18n:@click-to-show%</span>
 	</div>
 </div>
@@ -12,7 +12,7 @@
 		@click.prevent="onClick"
 		:title="video.name"
 	>
-		%fa:R play-circle%
+		<fa :icon="['far', 'play-circle']"/>
 	</a>
 </div>
 </template>
diff --git a/src/client/app/desktop/views/components/messaging-room-window.vue b/src/client/app/desktop/views/components/messaging-room-window.vue
index 370637760..7d7adc89d 100644
--- a/src/client/app/desktop/views/components/messaging-room-window.vue
+++ b/src/client/app/desktop/views/components/messaging-room-window.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-window ref="window" width="500px" height="560px" :popout-url="popout" @closed="destroyDom">
-	<span slot="header" :class="$style.header">%fa:comments%%i18n:@title% {{ user | userName }}</span>
+	<span slot="header" :class="$style.header"><fa icon="comments"/>%i18n:@title% {{ user | userName }}</span>
 	<mk-messaging-room :user="user" :class="$style.content"/>
 </mk-window>
 </template>
@@ -22,7 +22,7 @@ export default Vue.extend({
 
 <style lang="stylus" module>
 .header
-	> [data-fa]
+	> [data-icon]
 		margin-right 4px
 
 .content
diff --git a/src/client/app/desktop/views/components/messaging-window.vue b/src/client/app/desktop/views/components/messaging-window.vue
index a8f0fc68b..3ec07f2bc 100644
--- a/src/client/app/desktop/views/components/messaging-window.vue
+++ b/src/client/app/desktop/views/components/messaging-window.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-window ref="window" width="500px" height="560px" @closed="destroyDom">
-	<span slot="header" :class="$style.header">%fa:comments%%i18n:@title%</span>
+	<span slot="header" :class="$style.header"><fa icon="comments"/>%i18n:@title%</span>
 	<mk-messaging :class="$style.content" @navigate="navigate"/>
 </mk-window>
 </template>
@@ -22,7 +22,7 @@ export default Vue.extend({
 
 <style lang="stylus" module>
 .header
-	> [data-fa]
+	> [data-icon]
 		margin-right 4px
 
 .content
diff --git a/src/client/app/desktop/views/components/note-detail.vue b/src/client/app/desktop/views/components/note-detail.vue
index 1c802d790..8238c4824 100644
--- a/src/client/app/desktop/views/components/note-detail.vue
+++ b/src/client/app/desktop/views/components/note-detail.vue
@@ -7,8 +7,8 @@
 		@click="fetchConversation"
 		:disabled="conversationFetching"
 	>
-		<template v-if="!conversationFetching">%fa:ellipsis-v%</template>
-		<template v-if="conversationFetching">%fa:spinner .pulse%</template>
+		<template v-if="!conversationFetching"><fa icon="ellipsis-v"/></template>
+		<template v-if="conversationFetching"><fa icon="spinner .pulse"/></template>
 	</button>
 	<div class="conversation">
 		<x-sub v-for="note in conversation" :key="note.id" :note="note"/>
@@ -19,7 +19,7 @@
 	<div class="renote" v-if="isRenote">
 		<p>
 			<mk-avatar class="avatar" :user="note.user"/>
-			%fa:retweet%
+			<fa icon="retweet"/>
 			<router-link class="name" :href="note.user | userPage">{{ note.user | userName }}</router-link>
 			<span>{{ '%i18n:@reposted-by%'.substr(0, '%i18n:@reposted-by%'.indexOf('{')) }}</span>
 			<a class="name" :href="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</a>
@@ -52,7 +52,7 @@
 				</div>
 				<mk-poll v-if="p.poll" :note="p"/>
 				<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="true"/>
-				<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
+				<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank"><fa icon="map-marker-alt"/> %i18n:@location%</a>
 				<div class="map" v-if="p.geo" ref="map"></div>
 				<div class="renote" v-if="p.renote">
 					<mk-note-preview :note="p.renote"/>
@@ -62,18 +62,18 @@
 		<footer>
 			<mk-reactions-viewer :note="p"/>
 			<button class="replyButton" @click="reply" title="">
-				<template v-if="p.reply">%fa:reply-all%</template>
-				<template v-else>%fa:reply%</template>
+				<template v-if="p.reply"><fa icon="reply-all"/></template>
+				<template v-else><fa icon="reply"/></template>
 				<p class="count" v-if="p.repliesCount > 0">{{ p.repliesCount }}</p>
 			</button>
 			<button class="renoteButton" @click="renote" title="%i18n:@renote%">
-				%fa:retweet%<p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p>
+				<fa icon="retweet"/><p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p>
 			</button>
 			<button class="reactionButton" :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton" title="%i18n:@add-reaction%">
-				%fa:plus%<p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
+				<fa icon="plus"/><p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
 			</button>
 			<button @click="menu" ref="menuButton">
-				%fa:ellipsis-h%
+				<fa icon="ellipsis-h"/>
 			</button>
 		</footer>
 	</article>
@@ -278,7 +278,7 @@ export default Vue.extend({
 				margin 0 8px 0 0
 				border-radius 6px
 
-			[data-fa]
+			[data-icon]
 				margin-right 4px
 
 			.name
diff --git a/src/client/app/desktop/views/components/note.vue b/src/client/app/desktop/views/components/note.vue
index dd6cba9ce..0ccf59bc8 100644
--- a/src/client/app/desktop/views/components/note.vue
+++ b/src/client/app/desktop/views/components/note.vue
@@ -15,7 +15,7 @@
 	</div>
 	<div class="renote" v-if="isRenote">
 		<mk-avatar class="avatar" :user="note.user"/>
-		%fa:retweet%
+		<fa icon="retweet"/>
 		<span>{{ '%i18n:@reposted-by%'.substr(0, '%i18n:@reposted-by%'.indexOf('{')) }}</span>
 		<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
 		<span>{{ '%i18n:@reposted-by%'.substr('%i18n:@reposted-by%'.indexOf('}') + 1) }}</span>
@@ -33,7 +33,7 @@
 				<div class="content" v-show="appearNote.cw == null || showContent">
 					<div class="text">
 						<span v-if="appearNote.isHidden" style="opacity: 0.5">%i18n:@private%</span>
-						<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
+						<a class="reply" v-if="appearNote.reply"><fa icon="reply"/></a>
 						<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text" :customEmojis="appearNote.emojis"/>
 						<a class="rp" v-if="appearNote.renote">RN:</a>
 					</div>
@@ -41,7 +41,7 @@
 						<mk-media-list :media-list="appearNote.files"/>
 					</div>
 					<mk-poll v-if="appearNote.poll" :note="appearNote" ref="pollViewer"/>
-					<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
+					<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank"><fa icon="map-marker-alt"/> 位置情報</a>
 					<div class="renote" v-if="appearNote.renote"><mk-note-preview :note="appearNote.renote" :mini="mini"/></div>
 					<mk-url-preview v-for="url in urls" :url="url" :key="url" :mini="mini"/>
 				</div>
@@ -49,18 +49,18 @@
 			<footer>
 				<mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/>
 				<button class="replyButton" @click="reply()" title="%i18n:@reply%">
-					<template v-if="appearNote.reply">%fa:reply-all%</template>
-					<template v-else>%fa:reply%</template>
+					<template v-if="appearNote.reply"><fa icon="reply-all"/></template>
+					<template v-else><fa icon="reply"/></template>
 					<p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p>
 				</button>
 				<button class="renoteButton" @click="renote()" title="%i18n:@renote%">
-					%fa:retweet%<p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
+					<fa icon="retweet"/><p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
 				</button>
 				<button class="reactionButton" :class="{ reacted: appearNote.myReaction != null }" @click="react()" ref="reactButton" title="%i18n:@add-reaction%">
-					%fa:plus%<p class="count" v-if="appearNote.reactions_count > 0">{{ appearNote.reactions_count }}</p>
+					<fa icon="plus"/><p class="count" v-if="appearNote.reactions_count > 0">{{ appearNote.reactions_count }}</p>
 				</button>
 				<button @click="menu()" ref="menuButton">
-					%fa:ellipsis-h%
+					<fa icon="ellipsis-h"/>
 				</button>
 			</footer>
 		</div>
@@ -190,7 +190,7 @@ export default Vue.extend({
 			margin 0 8px 0 0
 			border-radius 6px
 
-		[data-fa]
+		[data-icon]
 			margin-right 4px
 
 		> span
diff --git a/src/client/app/desktop/views/components/notes.vue b/src/client/app/desktop/views/components/notes.vue
index 37ce2c9dd..7808ed742 100644
--- a/src/client/app/desktop/views/components/notes.vue
+++ b/src/client/app/desktop/views/components/notes.vue
@@ -17,8 +17,8 @@
 		<template v-for="(note, i) in _notes">
 			<x-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)" ref="note"/>
 			<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
-				<span>%fa:angle-up%{{ note._datetext }}</span>
-				<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
+				<span><fa icon="angle-up"/>{{ note._datetext }}</span>
+				<span><fa icon="angle-down"/>{{ _notes[i + 1]._datetext }}</span>
 			</p>
 		</template>
 	</component>
@@ -26,7 +26,7 @@
 	<footer v-if="more">
 		<button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
 			<template v-if="!moreFetching">%i18n:@load-more%</template>
-			<template v-if="moreFetching">%fa:spinner .pulse .fw%</template>
+			<template v-if="moreFetching"><fa icon="spinner .pulse" fixed-width/></template>
 		</button>
 	</footer>
 </div>
@@ -230,7 +230,7 @@ export default Vue.extend({
 			span
 				margin 0 16px
 
-			[data-fa]
+			[data-icon]
 				margin-right 8px
 
 	> .newer-indicator
diff --git a/src/client/app/desktop/views/components/notifications.vue b/src/client/app/desktop/views/components/notifications.vue
index e1a6c4c9a..09dbb899b 100644
--- a/src/client/app/desktop/views/components/notifications.vue
+++ b/src/client/app/desktop/views/components/notifications.vue
@@ -21,7 +21,7 @@
 								<router-link :to="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</router-link>
 							</p>
 							<router-link class="note-ref" :to="notification.note | notePage">
-								%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%
+								<fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}<fa icon="quote-right"/>
 							</router-link>
 						</div>
 					</template>
@@ -29,11 +29,11 @@
 					<template v-if="notification.type == 'renote'">
 						<mk-avatar class="avatar" :user="notification.note.user"/>
 						<div class="text">
-							<p>%fa:retweet%
+							<p><fa icon="retweet"/>
 								<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
 							</p>
 							<router-link class="note-ref" :to="notification.note | notePage">
-								%fa:quote-left%{{ getNoteSummary(notification.note.renote) }}%fa:quote-right%
+								<fa icon="quote-left"/>{{ getNoteSummary(notification.note.renote) }}<fa icon="quote-right"/>
 							</router-link>
 						</div>
 					</template>
@@ -41,7 +41,7 @@
 					<template v-if="notification.type == 'quote'">
 						<mk-avatar class="avatar" :user="notification.note.user"/>
 						<div class="text">
-							<p>%fa:quote-left%
+							<p><fa icon="quote-left"/>
 								<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
 							</p>
 							<router-link class="note-preview" :to="notification.note | notePage">{{ getNoteSummary(notification.note) }}</router-link>
@@ -51,7 +51,7 @@
 					<template v-if="notification.type == 'follow'">
 						<mk-avatar class="avatar" :user="notification.user"/>
 						<div class="text">
-							<p>%fa:user-plus%
+							<p><fa icon="user-plus"/>
 								<router-link :to="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</router-link>
 							</p>
 						</div>
@@ -60,7 +60,7 @@
 					<template v-if="notification.type == 'receiveFollowRequest'">
 						<mk-avatar class="avatar" :user="notification.user"/>
 						<div class="text">
-							<p>%fa:user-clock%
+							<p><fa icon="user-clock"/>
 								<router-link :to="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</router-link>
 							</p>
 						</div>
@@ -69,7 +69,7 @@
 					<template v-if="notification.type == 'reply'">
 						<mk-avatar class="avatar" :user="notification.note.user"/>
 						<div class="text">
-							<p>%fa:reply%
+							<p><fa icon="reply"/>
 								<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
 							</p>
 							<router-link class="note-preview" :to="notification.note | notePage">{{ getNoteSummary(notification.note) }}</router-link>
@@ -79,7 +79,7 @@
 					<template v-if="notification.type == 'mention'">
 						<mk-avatar class="avatar" :user="notification.note.user"/>
 						<div class="text">
-							<p>%fa:at%
+							<p><fa icon="at"/>
 								<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
 							</p>
 							<a class="note-preview" :href="notification.note | notePage">{{ getNoteSummary(notification.note) }}</a>
@@ -89,23 +89,23 @@
 					<template v-if="notification.type == 'poll_vote'">
 						<mk-avatar class="avatar" :user="notification.user"/>
 						<div class="text">
-							<p>%fa:chart-pie%<a :href="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</a></p>
+							<p><fa icon="chart-pie"/><a :href="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</a></p>
 							<router-link class="note-ref" :to="notification.note | notePage">
-								%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%
+								<fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}<fa icon="quote-right"/>
 							</router-link>
 						</div>
 					</template>
 				</div>
 
 				<p class="date" v-if="i != notifications.length - 1 && notification._date != _notifications[i + 1]._date" :key="notification.id + '-time'">
-					<span>%fa:angle-up%{{ notification._datetext }}</span>
-					<span>%fa:angle-down%{{ _notifications[i + 1]._datetext }}</span>
+					<span><fa icon="angle-up"/>{{ notification._datetext }}</span>
+					<span><fa icon="angle-down"/>{{ _notifications[i + 1]._datetext }}</span>
 				</p>
 			</template>
 		</component>
 	</div>
 	<button class="more" :class="{ fetching: fetchingMoreNotifications }" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications">
-		<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
+		<template v-if="fetchingMoreNotifications"><fa icon="spinner .pulse" fixed-width/></template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
 	</button>
 	<p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:@empty%</p>
 </div>
@@ -264,7 +264,7 @@ export default Vue.extend({
 				.note-ref
 					color var(--noteText)
 
-					[data-fa]
+					[data-icon]
 						font-size 1em
 						font-weight normal
 						font-style normal
@@ -300,7 +300,7 @@ export default Vue.extend({
 				span
 					margin 0 16px
 
-				[data-fa]
+				[data-icon]
 					margin-right 8px
 
 	> .more
@@ -319,7 +319,7 @@ export default Vue.extend({
 		&.fetching
 			cursor wait
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 
 	> .empty
diff --git a/src/client/app/desktop/views/components/post-form-window.vue b/src/client/app/desktop/views/components/post-form-window.vue
index a5d191f2f..347304539 100644
--- a/src/client/app/desktop/views/components/post-form-window.vue
+++ b/src/client/app/desktop/views/components/post-form-window.vue
@@ -1,7 +1,7 @@
 <template>
 <mk-window class="mk-post-form-window" ref="window" is-modal @closed="onWindowClosed" :animation="animation">
 	<span slot="header" class="mk-post-form-window--header">
-		<span class="icon" v-if="geo">%fa:map-marker-alt%</span>
+		<span class="icon" v-if="geo"><fa icon="map-marker-alt"/></span>
 		<span v-if="!reply">%i18n:@note%</span>
 		<span v-if="reply">%i18n:@reply%</span>
 		<span class="count" v-if="files.length != 0">{{ '%i18n:@attaches%'.replace('{}', files.length) }}</span>
diff --git a/src/client/app/desktop/views/components/post-form.vue b/src/client/app/desktop/views/components/post-form.vue
index a703382f3..e6d3fd693 100644
--- a/src/client/app/desktop/views/components/post-form.vue
+++ b/src/client/app/desktop/views/components/post-form.vue
@@ -32,18 +32,18 @@
 		<mk-poll-editor v-if="poll" ref="poll" @destroyed="poll = false" @updated="saveDraft()"/>
 	</div>
 	<mk-uploader ref="uploader" @uploaded="attachMedia" @change="onChangeUploadings"/>
-	<button class="upload" title="%i18n:@attach-media-from-local%" @click="chooseFile">%fa:upload%</button>
-	<button class="drive" title="%i18n:@attach-media-from-drive%" @click="chooseFileFromDrive">%fa:cloud%</button>
-	<button class="kao" title="%i18n:@insert-a-kao%" @click="kao">%fa:R smile%</button>
-	<button class="poll" title="%i18n:@create-poll%" @click="poll = !poll">%fa:chart-pie%</button>
-	<button class="poll" title="%i18n:@hide-contents%" @click="useCw = !useCw">%fa:eye-slash%</button>
-	<button class="geo" title="%i18n:@attach-location-information%" @click="geo ? removeGeo() : setGeo()">%fa:map-marker-alt%</button>
+	<button class="upload" title="%i18n:@attach-media-from-local%" @click="chooseFile"><fa icon="upload"/></button>
+	<button class="drive" title="%i18n:@attach-media-from-drive%" @click="chooseFileFromDrive"><fa icon="cloud"/></button>
+	<button class="kao" title="%i18n:@insert-a-kao%" @click="kao"><fa :icon="['far', 'smile']"/></button>
+	<button class="poll" title="%i18n:@create-poll%" @click="poll = !poll"><fa icon="chart-pie"/></button>
+	<button class="poll" title="%i18n:@hide-contents%" @click="useCw = !useCw"><fa icon="eye-slash"/></button>
+	<button class="geo" title="%i18n:@attach-location-information%" @click="geo ? removeGeo() : setGeo()"><fa icon="map-marker-alt"/></button>
 	<button class="visibility" title="%i18n:@visibility%" @click="setVisibility" ref="visibilityButton">
-		<span v-if="visibility === 'public'">%fa:globe%</span>
-		<span v-if="visibility === 'home'">%fa:home%</span>
-		<span v-if="visibility === 'followers'">%fa:unlock%</span>
-		<span v-if="visibility === 'specified'">%fa:envelope%</span>
-		<span v-if="visibility === 'private'">%fa:lock%</span>
+		<span v-if="visibility === 'public'"><fa icon="globe"/></span>
+		<span v-if="visibility === 'home'"><fa icon="home"/></span>
+		<span v-if="visibility === 'followers'"><fa icon="unlock"/></span>
+		<span v-if="visibility === 'specified'"><fa icon="envelope"/></span>
+		<span v-if="visibility === 'private'"><fa icon="lock"/></span>
 	</button>
 	<p class="text-count" :class="{ over: this.trimmedLength(text) > this.maxNoteTextLength }">{{ this.maxNoteTextLength - this.trimmedLength(text) }}</p>
 	<button :class="{ posting }" class="submit" :disabled="!canPost" @click="post">
diff --git a/src/client/app/desktop/views/components/received-follow-requests-window.vue b/src/client/app/desktop/views/components/received-follow-requests-window.vue
index 3df1329c4..5ebe0cc35 100644
--- a/src/client/app/desktop/views/components/received-follow-requests-window.vue
+++ b/src/client/app/desktop/views/components/received-follow-requests-window.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-window ref="window" is-modal width="450px" height="500px" @closed="destroyDom">
-	<span slot="header">%fa:envelope R% %i18n:@title%</span>
+	<span slot="header"><fa :icon="['far', 'envelope']"/> %i18n:@title%</span>
 
 	<div class="slpqaxdoxhvglersgjukmvizkqbmbokc">
 		<div v-for="req in requests">
diff --git a/src/client/app/desktop/views/components/renote-form-window.vue b/src/client/app/desktop/views/components/renote-form-window.vue
index b9760fcbe..933f10475 100644
--- a/src/client/app/desktop/views/components/renote-form-window.vue
+++ b/src/client/app/desktop/views/components/renote-form-window.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-window ref="window" is-modal @closed="onWindowClosed" :animation="animation">
-	<span slot="header" :class="$style.header">%fa:retweet%%i18n:@title%</span>
+	<span slot="header" :class="$style.header"><fa icon="retweet"/>%i18n:@title%</span>
 	<mk-renote-form ref="form" :note="note" @posted="onPosted" @canceled="onCanceled" v-hotkey.global="keymap"/>
 </mk-window>
 </template>
@@ -58,7 +58,7 @@ export default Vue.extend({
 
 <style lang="stylus" module>
 .header
-	> [data-fa]
+	> [data-icon]
 		margin-right 4px
 
 </style>
diff --git a/src/client/app/desktop/views/components/settings-window.vue b/src/client/app/desktop/views/components/settings-window.vue
index 424771774..b69c40e0e 100644
--- a/src/client/app/desktop/views/components/settings-window.vue
+++ b/src/client/app/desktop/views/components/settings-window.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-window ref="window" is-modal width="700px" height="550px" @closed="destroyDom">
-	<span slot="header" :class="$style.header">%fa:cog%%i18n:@settings%</span>
+	<span slot="header" :class="$style.header"><fa icon="cog"/>%i18n:@settings%</span>
 	<mk-settings :initial-page="initialPage" @done="close"/>
 </mk-window>
 </template>
@@ -24,7 +24,7 @@ export default Vue.extend({
 
 <style lang="stylus" module>
 .header
-	> [data-fa]
+	> [data-icon]
 		margin-right 4px
 
 </style>
diff --git a/src/client/app/desktop/views/components/settings.2fa.vue b/src/client/app/desktop/views/components/settings.2fa.vue
index 001830712..3d349947e 100644
--- a/src/client/app/desktop/views/components/settings.2fa.vue
+++ b/src/client/app/desktop/views/components/settings.2fa.vue
@@ -16,7 +16,7 @@
 				<ui-button primary @click="submit">%i18n:@submit%</ui-button>
 			</li>
 		</ol>
-		<div class="ui info"><p>%fa:info-circle%%i18n:@info%</p></div>
+		<div class="ui info"><p><fa icon="info-circle"/>%i18n:@info%</p></div>
 	</div>
 </div>
 </template>
diff --git a/src/client/app/desktop/views/components/settings.signins.vue b/src/client/app/desktop/views/components/settings.signins.vue
index 7d1bb4f4e..1bc3bd0ad 100644
--- a/src/client/app/desktop/views/components/settings.signins.vue
+++ b/src/client/app/desktop/views/components/settings.signins.vue
@@ -3,13 +3,13 @@
 <div class="signins" v-if="signins.length != 0">
 	<div v-for="signin in signins">
 		<header @click="signin._show = !signin._show">
-			<template v-if="signin.success">%fa:check%</template>
-			<template v-else>%fa:times%</template>
+			<template v-if="signin.success"><fa icon="check"/></template>
+			<template v-else><fa icon="times"/></template>
 			<span class="ip">{{ signin.ip }}</span>
 			<mk-time :time="signin.createdAt"/>
 		</header>
 		<div class="headers" v-show="signin._show">
-			<tree-view :data="signin.headers"/>
+			<!-- TODO -->
 		</div>
 	</div>
 </div>
@@ -62,7 +62,7 @@ export default Vue.extend({
 				line-height 32px
 				cursor pointer
 
-				> [data-fa]
+				> [data-icon]
 					margin-right 8px
 					text-align left
 
diff --git a/src/client/app/desktop/views/components/settings.vue b/src/client/app/desktop/views/components/settings.vue
index 97743b0bf..6aa047d01 100644
--- a/src/client/app/desktop/views/components/settings.vue
+++ b/src/client/app/desktop/views/components/settings.vue
@@ -1,31 +1,31 @@
 <template>
 <div class="mk-settings">
 	<div class="nav">
-		<p :class="{ active: page == 'profile' }" @mousedown="page = 'profile'">%fa:user .fw%%i18n:@profile%</p>
-		<p :class="{ active: page == 'theme' }" @mousedown="page = 'theme'">%fa:palette .fw%%i18n:@theme%</p>
-		<p :class="{ active: page == 'web' }" @mousedown="page = 'web'">%fa:desktop .fw%Web</p>
-		<p :class="{ active: page == 'notification' }" @mousedown="page = 'notification'">%fa:R bell .fw%%i18n:@notification%</p>
-		<p :class="{ active: page == 'drive' }" @mousedown="page = 'drive'">%fa:cloud .fw%%i18n:common.drive%</p>
-		<p :class="{ active: page == 'hashtags' }" @mousedown="page = 'hashtags'">%fa:hashtag .fw%%i18n:@tags%</p>
-		<p :class="{ active: page == 'muteAndBlock' }" @mousedown="page = 'muteAndBlock'">%fa:ban .fw%%i18n:@mute-and-block%</p>
-		<p :class="{ active: page == 'apps' }" @mousedown="page = 'apps'">%fa:puzzle-piece .fw%%i18n:@apps%</p>
-		<p :class="{ active: page == 'security' }" @mousedown="page = 'security'">%fa:unlock-alt .fw%%i18n:@security%</p>
-		<p :class="{ active: page == 'api' }" @mousedown="page = 'api'">%fa:key .fw%API</p>
-		<p :class="{ active: page == 'other' }" @mousedown="page = 'other'">%fa:cogs .fw%%i18n:@other%</p>
+		<p :class="{ active: page == 'profile' }" @mousedown="page = 'profile'"><fa icon="user" fixed-width/>%i18n:@profile%</p>
+		<p :class="{ active: page == 'theme' }" @mousedown="page = 'theme'"><fa icon="palette" fixed-width/>%i18n:@theme%</p>
+		<p :class="{ active: page == 'web' }" @mousedown="page = 'web'"><fa icon="desktop" fixed-width/>Web</p>
+		<p :class="{ active: page == 'notification' }" @mousedown="page = 'notification'"><fa :icon="['far', 'bell']" fixed-width/>%i18n:@notification%</p>
+		<p :class="{ active: page == 'drive' }" @mousedown="page = 'drive'"><fa icon="cloud" fixed-width/>%i18n:common.drive%</p>
+		<p :class="{ active: page == 'hashtags' }" @mousedown="page = 'hashtags'"><fa icon="hashtag" fixed-width/>%i18n:@tags%</p>
+		<p :class="{ active: page == 'muteAndBlock' }" @mousedown="page = 'muteAndBlock'"><fa icon="ban" fixed-width/>%i18n:@mute-and-block%</p>
+		<p :class="{ active: page == 'apps' }" @mousedown="page = 'apps'"><fa icon="puzzle-piece" fixed-width/>%i18n:@apps%</p>
+		<p :class="{ active: page == 'security' }" @mousedown="page = 'security'"><fa icon="unlock-alt" fixed-width/>%i18n:@security%</p>
+		<p :class="{ active: page == 'api' }" @mousedown="page = 'api'"><fa icon="key" fixed-width/>API</p>
+		<p :class="{ active: page == 'other' }" @mousedown="page = 'other'"><fa icon="cogs" fixed-width/>%i18n:@other%</p>
 	</div>
 	<div class="pages">
 		<div class="profile" v-show="page == 'profile'">
 			<mk-profile-editor/>
 
 			<ui-card>
-				<div slot="title">%fa:B twitter% %i18n:@twitter%</div>
+				<div slot="title"><fa :icon="['fab', 'twitter']"/> %i18n:@twitter%</div>
 				<section>
 					<mk-twitter-setting/>
 				</section>
 			</ui-card>
 
 			<ui-card>
-				<div slot="title">%fa:B github% %i18n:@github%</div>
+				<div slot="title"><fa :icon="['fab', 'github']"/> %i18n:@github%</div>
 				<section>
 					<mk-github-setting/>
 				</section>
@@ -33,7 +33,7 @@
 		</div>
 
 		<ui-card class="theme" v-show="page == 'theme'">
-			<div slot="title">%fa:palette% %i18n:@theme%</div>
+			<div slot="title"><fa icon="palette"/> %i18n:@theme%</div>
 
 			<section>
 				<mk-theme/>
@@ -41,7 +41,7 @@
 		</ui-card>
 
 		<ui-card class="web" v-show="page == 'web'">
-			<div slot="title">%fa:sliders-h% %i18n:@behaviour%</div>
+			<div slot="title"><fa icon="sliders-h"/> %i18n:@behaviour%</div>
 
 			<section>
 				<ui-switch v-model="fetchOnScroll">
@@ -87,7 +87,7 @@
 		</ui-card>
 
 		<ui-card class="web" v-show="page == 'web'">
-			<div slot="title">%fa:desktop% %i18n:@display%</div>
+			<div slot="title"><fa icon="desktop"/> %i18n:@display%</div>
 
 			<section>
 				<ui-switch v-model="showPostFormOnTopOfTl">%i18n:@post-form-on-timeline%</ui-switch>
@@ -138,7 +138,7 @@
 		</ui-card>
 
 		<ui-card class="web" v-show="page == 'web'">
-			<div slot="title">%fa:volume-up% %i18n:@sound%</div>
+			<div slot="title"><fa icon="volume-up"/> %i18n:@sound%</div>
 
 			<section>
 				<ui-switch v-model="enableSounds">
@@ -152,12 +152,12 @@
 					max="1"
 					step="0.1"
 				/>
-				<ui-button @click="soundTest">%fa:volume-up% %i18n:@test%</ui-button>
+				<ui-button @click="soundTest"><fa icon="volume-up"/> %i18n:@test%</ui-button>
 			</section>
 		</ui-card>
 
 		<ui-card class="web" v-show="page == 'web'">
-			<div slot="title">%fa:language% %i18n:@language%</div>
+			<div slot="title"><fa icon="language"/> %i18n:@language%</div>
 			<section class="fit-top">
 				<ui-select v-model="lang" placeholder="%i18n:@pick-language%">
 					<optgroup label="%i18n:@recommended%">
@@ -169,23 +169,23 @@
 					</optgroup>
 				</ui-select>
 				<div class="none ui info">
-					<p>%fa:info-circle%%i18n:@language-desc%</p>
+					<p><fa icon="info-circle"/>%i18n:@language-desc%</p>
 				</div>
 			</section>
 		</ui-card>
 
 		<ui-card class="web" v-show="page == 'web'">
-			<div slot="title">%fa:trash-alt R% %i18n:@cache%</div>
+			<div slot="title"><fa :icon="['far', 'trash-alt']"/> %i18n:@cache%</div>
 			<section>
 				<ui-button @click="clean">%i18n:@clean-cache%</ui-button>
 				<div class="none ui info warn">
-					<p>%fa:exclamation-triangle%%i18n:@cache-warn%</p>
+					<p><fa icon="exclamation-triangle"/>%i18n:@cache-warn%</p>
 				</div>
 			</section>
 		</ui-card>
 
 		<ui-card class="notification" v-show="page == 'notification'">
-			<div slot="title">%fa:bell R% %i18n:@notification%</div>
+			<div slot="title"><fa :icon="['far', 'bell']"/> %i18n:@notification%</div>
 			<section>
 				<ui-switch v-model="$store.state.i.settings.autoWatch" @change="onChangeAutoWatch">
 					%i18n:@auto-watch%
@@ -202,7 +202,7 @@
 		</div>
 
 		<ui-card class="hashtags" v-show="page == 'hashtags'">
-			<div slot="title">%fa:hashtag% %i18n:@tags%</div>
+			<div slot="title"><fa icon="hashtag"/> %i18n:@tags%</div>
 			<section>
 				<x-tags/>
 			</section>
@@ -213,28 +213,28 @@
 		</div>
 
 		<ui-card class="apps" v-show="page == 'apps'">
-			<div slot="title">%fa:puzzle-piece% %i18n:@apps%</div>
+			<div slot="title"><fa icon="puzzle-piece"/> %i18n:@apps%</div>
 			<section>
 				<x-apps/>
 			</section>
 		</ui-card>
 
 		<ui-card class="password" v-show="page == 'security'">
-			<div slot="title">%fa:unlock-alt% %i18n:@password%</div>
+			<div slot="title"><fa icon="unlock-alt"/> %i18n:@password%</div>
 			<section>
 				<mk-password-settings/>
 			</section>
 		</ui-card>
 
 		<ui-card class="2fa" v-show="page == 'security'">
-			<div slot="title">%fa:mobile-alt% %i18n:@2fa%</div>
+			<div slot="title"><fa icon="mobile-alt"/> %i18n:@2fa%</div>
 			<section>
 				<x-2fa/>
 			</section>
 		</ui-card>
 
 		<ui-card class="signin" v-show="page == 'security'">
-			<div slot="title">%fa:sign-in-alt% %i18n:@signin%</div>
+			<div slot="title"><fa icon="sign-in-alt"/> %i18n:@signin%</div>
 			<section>
 				<x-signins/>
 			</section>
@@ -245,14 +245,14 @@
 		</div>
 
 		<ui-card class="other" v-show="page == 'other'">
-			<div slot="title">%fa:info-circle% %i18n:@about%</div>
+			<div slot="title"><fa icon="info-circle"/> %i18n:@about%</div>
 			<section>
 				<p v-if="meta">%i18n:@operator%: <i><a :href="meta.maintainer.url" target="_blank">{{ meta.maintainer.name }}</a></i></p>
 			</section>
 		</ui-card>
 
 		<ui-card class="other" v-show="page == 'other'">
-			<div slot="title">%fa:sync-alt% %i18n:@update%</div>
+			<div slot="title"><fa icon="sync-alt"/> %i18n:@update%</div>
 			<section>
 				<p>
 					<span>%i18n:@version% <i>{{ version }}</i></span>
@@ -276,7 +276,7 @@
 		</ui-card>
 
 		<ui-card class="other" v-show="page == 'other'">
-			<div slot="title">%fa:cogs% %i18n:@advanced-settings%</div>
+			<div slot="title"><fa icon="cogs"/> %i18n:@advanced-settings%</div>
 			<section>
 				<ui-switch v-model="debug">
 					%i18n:@debug-mode%
@@ -595,7 +595,7 @@ export default Vue.extend({
 			user-select none
 			transition margin-left 0.2s ease
 
-			> [data-fa]
+			> [data-icon]
 				margin-right 4px
 
 			&:hover
diff --git a/src/client/app/desktop/views/components/sub-note-content.vue b/src/client/app/desktop/views/components/sub-note-content.vue
index b5e4e008d..c17b5ccea 100644
--- a/src/client/app/desktop/views/components/sub-note-content.vue
+++ b/src/client/app/desktop/views/components/sub-note-content.vue
@@ -3,7 +3,7 @@
 	<div class="body">
 		<span v-if="note.isHidden" style="opacity: 0.5">%i18n:@private%</span>
 		<span v-if="note.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
-		<a class="reply" v-if="note.replyId">%fa:reply%</a>
+		<a class="reply" v-if="note.replyId"><fa icon="reply"/></a>
 		<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i" :customEmojis="note.emojis"/>
 		<a class="rp" v-if="note.renoteId" :href="`/notes/${note.renoteId}`">RN: ...</a>
 	</div>
diff --git a/src/client/app/desktop/views/components/timeline.core.vue b/src/client/app/desktop/views/components/timeline.core.vue
index f1af7116b..91b3cd5f2 100644
--- a/src/client/app/desktop/views/components/timeline.core.vue
+++ b/src/client/app/desktop/views/components/timeline.core.vue
@@ -4,7 +4,7 @@
 
 	<mk-notes ref="timeline" :more="existMore ? more : null">
 		<p :class="$style.empty" slot="empty">
-			%fa:R comments%%i18n:@empty%
+			<fa :icon="['far', 'comments']"/>%i18n:@empty%
 		</p>
 	</mk-notes>
 </div>
@@ -182,7 +182,7 @@ export default Vue.extend({
 	text-align center
 	color #999
 
-	> [data-fa]
+	> [data-icon]
 		display block
 		margin-bottom 16px
 		font-size 3em
diff --git a/src/client/app/desktop/views/components/timeline.vue b/src/client/app/desktop/views/components/timeline.vue
index 3e4c45d22..336033b60 100644
--- a/src/client/app/desktop/views/components/timeline.vue
+++ b/src/client/app/desktop/views/components/timeline.vue
@@ -1,17 +1,17 @@
 <template>
 <div class="mk-timeline">
 	<header>
-		<span :data-active="src == 'home'" @click="src = 'home'">%fa:home% %i18n:@home%</span>
-		<span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline">%fa:R comments% %i18n:@local%</span>
-		<span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline">%fa:share-alt% %i18n:@hybrid%</span>
-		<span :data-active="src == 'global'" @click="src = 'global'">%fa:globe% %i18n:@global%</span>
-		<span :data-active="src == 'tag'" @click="src = 'tag'" v-if="tagTl">%fa:hashtag% {{ tagTl.title }}</span>
-		<span :data-active="src == 'list'" @click="src = 'list'" v-if="list">%fa:list% {{ list.title }}</span>
+		<span :data-active="src == 'home'" @click="src = 'home'"><fa icon="home"/> %i18n:@home%</span>
+		<span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline"><fa :icon="['far', 'comments']"/> %i18n:@local%</span>
+		<span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline"><fa icon="share-alt"/> %i18n:@hybrid%</span>
+		<span :data-active="src == 'global'" @click="src = 'global'"><fa icon="globe"/> %i18n:@global%</span>
+		<span :data-active="src == 'tag'" @click="src = 'tag'" v-if="tagTl"><fa icon="hashtag"/> {{ tagTl.title }}</span>
+		<span :data-active="src == 'list'" @click="src = 'list'" v-if="list"><fa icon="list"/> {{ list.title }}</span>
 		<div class="buttons">
-			<button :data-active="src == 'mentions'" @click="src = 'mentions'" title="%i18n:@mentions%">%fa:at%<i class="badge" v-if="$store.state.i.hasUnreadMentions">%fa:circle%</i></button>
-			<button :data-active="src == 'messages'" @click="src = 'messages'" title="%i18n:@messages%">%fa:envelope R%<i class="badge" v-if="$store.state.i.hasUnreadSpecifiedNotes">%fa:circle%</i></button>
-			<button @click="chooseTag" title="%i18n:@hashtag%" ref="tagButton">%fa:hashtag%</button>
-			<button @click="chooseList" title="%i18n:@list%" ref="listButton">%fa:list%</button>
+			<button :data-active="src == 'mentions'" @click="src = 'mentions'" title="%i18n:@mentions%"><fa icon="at"/><i class="badge" v-if="$store.state.i.hasUnreadMentions"><fa icon="circle"/></i></button>
+			<button :data-active="src == 'messages'" @click="src = 'messages'" title="%i18n:@messages%"><fa :icon="['far', 'envelope']"/><i class="badge" v-if="$store.state.i.hasUnreadSpecifiedNotes"><fa icon="circle"/></i></button>
+			<button @click="chooseTag" title="%i18n:@hashtag%" ref="tagButton"><fa icon="hashtag"/></button>
+			<button @click="chooseList" title="%i18n:@list%" ref="listButton"><fa icon="list"/></button>
 		</div>
 	</header>
 	<x-core v-if="src == 'home'" ref="tl" key="home" src="home"/>
@@ -104,7 +104,7 @@ export default Vue.extend({
 			const lists = await (this as any).api('users/lists/list');
 
 			let menu = [{
-				icon: '%fa:plus%',
+				icon: 'plus',
 				text: '%i18n:@add-list%',
 				action: () => {
 					(this as any).apis.input({
@@ -125,7 +125,7 @@ export default Vue.extend({
 			}
 
 			menu = menu.concat(lists.map(list => ({
-				icon: '%fa:list%',
+				icon: 'list',
 				text: list.title,
 				action: () => {
 					this.list = list;
@@ -142,7 +142,7 @@ export default Vue.extend({
 
 		chooseTag() {
 			let menu = [{
-				icon: '%fa:plus%',
+				icon: 'plus',
 				text: '%i18n:@add-tag-timeline%',
 				action: () => {
 					(this as any).os.new(MkSettingsWindow, {
@@ -156,7 +156,7 @@ export default Vue.extend({
 			}
 
 			menu = menu.concat(this.$store.state.settings.tagTimelines.map(t => ({
-				icon: '%fa:hashtag%',
+				icon: 'hashtag',
 				text: t.title,
 				action: () => {
 					this.tagTl = t;
diff --git a/src/client/app/desktop/views/components/ui.header.account.vue b/src/client/app/desktop/views/components/ui.header.account.vue
index fd5e8338d..31118b014 100644
--- a/src/client/app/desktop/views/components/ui.header.account.vue
+++ b/src/client/app/desktop/views/components/ui.header.account.vue
@@ -1,47 +1,86 @@
 <template>
 <div class="account" v-hotkey.global="keymap">
 	<button class="header" :data-active="isOpen" @click="toggle">
-		<span class="username">{{ $store.state.i.username }}<template v-if="!isOpen">%fa:angle-down%</template><template v-if="isOpen">%fa:angle-up%</template></span>
+		<span class="username">{{ $store.state.i.username }}<template v-if="!isOpen"><fa icon="angle-down"/></template><template v-if="isOpen"><fa icon="angle-up"/></template></span>
 		<mk-avatar class="avatar" :user="$store.state.i"/>
 	</button>
 	<transition name="zoom-in-top">
 		<div class="menu" v-if="isOpen">
 			<ul>
 				<li>
-					<router-link :to="`/@${ $store.state.i.username }`">%fa:user%<span>%i18n:@profile%</span>%fa:angle-right%</router-link>
+					<router-link :to="`/@${ $store.state.i.username }`">
+						<i><fa icon="user"/></i>
+						<span>%i18n:@profile%</span>
+						<i><fa icon="angle-right"/></i>
+					</router-link>
 				</li>
 				<li @click="drive">
-					<p>%fa:cloud%<span>%i18n:common.drive%</span>%fa:angle-right%</p>
+					<p>
+						<i><fa icon="cloud"/></i>
+						<span>%i18n:common.drive%</span>
+						<i><fa icon="angle-right"/></i>
+					</p>
 				</li>
 				<li>
-					<router-link to="/i/favorites">%fa:star%<span>%i18n:@favorites%</span>%fa:angle-right%</router-link>
+					<router-link to="/i/favorites">
+						<i><fa icon="star"/></i>
+						<span>%i18n:@favorites%</span>
+						<i><fa icon="angle-right"/></i>
+					</router-link>
 				</li>
 				<li @click="list">
-					<p>%fa:list%<span>%i18n:@lists%</span>%fa:angle-right%</p>
+					<p>
+						<i><fa icon="list"/></i>
+						<span>%i18n:@lists%</span>
+						<i><fa icon="angle-right"/></i>
+					</p>
 				</li>
 				<li @click="followRequests" v-if="($store.state.i.isLocked || $store.state.i.carefulBot)">
-					<p>%fa:envelope R%<span>%i18n:@follow-requests%<i v-if="$store.state.i.pendingReceivedFollowRequestsCount">{{ $store.state.i.pendingReceivedFollowRequestsCount }}</i></span>%fa:angle-right%</p>
+					<p>
+						<i><fa :icon="['far', 'envelope']"/></i>
+						<span>%i18n:@follow-requests%<i v-if="$store.state.i.pendingReceivedFollowRequestsCount">{{ $store.state.i.pendingReceivedFollowRequestsCount }}</i></span>
+						<i><fa icon="angle-right"/></i>
+					</p>
 				</li>
 			</ul>
 			<ul>
 				<li>
-					<router-link to="/i/customize-home">%fa:wrench%<span>%i18n:@customize%</span>%fa:angle-right%</router-link>
+					<router-link to="/i/customize-home">
+						<i><fa icon="wrench"/></i>
+						<span>%i18n:@customize%</span>
+						<i><fa icon="angle-right"/></i>
+					</router-link>
 				</li>
 				<li @click="settings">
-					<p>%fa:cog%<span>%i18n:@settings%</span>%fa:angle-right%</p>
+					<p>
+						<i><fa icon="cog"/></i>
+						<span>%i18n:@settings%</span>
+						<i><fa icon="angle-right"/></i>
+					</p>
 				</li>
 				<li v-if="$store.state.i.isAdmin">
-					<a href="/admin">%fa:terminal%<span>%i18n:@admin%</span>%fa:angle-right%</a>
+					<a href="/admin">
+						<i><fa icon="terminal"/></i>
+						<span>%i18n:@admin%</span>
+						<i><fa icon="angle-right"/></i>
+					</a>
 				</li>
 			</ul>
 			<ul>
 				<li @click="dark">
-					<p><span>%i18n:@dark%</span><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template></p>
+					<p>
+						<span>%i18n:@dark%</span>
+						<template v-if="$store.state.device.darkmode"><i><fa icon="moon"/></i></template>
+						<template v-else><i><fa :icon="['far', 'moon']"/></i></template>
+					</p>
 				</li>
 			</ul>
 			<ul>
 				<li @click="signout">
-					<p class="signout">%fa:power-off%<span>%i18n:@signout%</span></p>
+					<p class="signout">
+						<i><fa icon="power-off"/></i>
+						<span>%i18n:@signout%</span>
+					</p>
 				</li>
 			</ul>
 		</div>
@@ -160,7 +199,7 @@ export default Vue.extend({
 			@media (max-width 1100px)
 				display none
 
-			[data-fa]
+			[data-icon]
 				margin-left 8px
 
 		> .avatar
@@ -254,11 +293,11 @@ export default Vue.extend({
 							color var(--primaryForeground)
 							border-radius 8px
 
-					> [data-fa]:first-child
+					> i:first-child
 						margin-right 6px
 						width 16px
 
-					> [data-fa]:last-child
+					> i:last-child
 						display block
 						position absolute
 						top 0
diff --git a/src/client/app/desktop/views/components/ui.header.nav.vue b/src/client/app/desktop/views/components/ui.header.nav.vue
index 3acc25c0d..585f0a943 100644
--- a/src/client/app/desktop/views/components/ui.header.nav.vue
+++ b/src/client/app/desktop/views/components/ui.header.nav.vue
@@ -4,32 +4,32 @@
 		<template v-if="$store.getters.isSignedIn">
 			<template v-if="$store.state.device.deckDefault">
 				<li class="deck" :class="{ active: $route.name == 'deck' || $route.name == 'index' }" @click="goToTop">
-					<router-link to="/">%fa:columns%<p>%i18n:@deck%</p></router-link>
+					<router-link to="/"><fa icon="columns"/><p>%i18n:@deck%</p></router-link>
 				</li>
 				<li class="home" :class="{ active: $route.name == 'home' }" @click="goToTop">
-					<router-link to="/home">%fa:home%<p>%i18n:@home%</p></router-link>
+					<router-link to="/home"><fa icon="home"/><p>%i18n:@home%</p></router-link>
 				</li>
 			</template>
 			<template v-else>
 				<li class="home" :class="{ active: $route.name == 'home' || $route.name == 'index' }" @click="goToTop">
-					<router-link to="/">%fa:home%<p>%i18n:@home%</p></router-link>
+					<router-link to="/"><fa icon="home"/><p>%i18n:@home%</p></router-link>
 				</li>
 				<li class="deck" :class="{ active: $route.name == 'deck' }" @click="goToTop">
-					<router-link to="/deck">%fa:columns%<p>%i18n:@deck%</p></router-link>
+					<router-link to="/deck"><fa icon="columns"/><p>%i18n:@deck%</p></router-link>
 				</li>
 			</template>
 			<li class="messaging">
 				<a @click="messaging">
-					%fa:comments%
+					<fa icon="comments"/>
 					<p>%i18n:@messaging%</p>
-					<template v-if="hasUnreadMessagingMessage">%fa:circle%</template>
+					<template v-if="hasUnreadMessagingMessage"><fa icon="circle"/></template>
 				</a>
 			</li>
 			<li class="game">
 				<a @click="game">
-					%fa:gamepad%
+					<fa icon="gamepad"/>
 					<p>%i18n:@game%</p>
-					<template v-if="hasGameInvitations">%fa:circle%</template>
+					<template v-if="hasGameInvitations"><fa icon="circle"/></template>
 				</a>
 			</li>
 		</template>
@@ -139,10 +139,10 @@ export default Vue.extend({
 					color var(--desktopHeaderHoverFg)
 					text-decoration none
 
-				> [data-fa]:first-child
+				> [data-icon]:first-child
 					margin-right 8px
 
-				> [data-fa]:last-child
+				> [data-icon]:last-child
 					margin-left 5px
 					font-size 10px
 					color var(--primary)
diff --git a/src/client/app/desktop/views/components/ui.header.notifications.vue b/src/client/app/desktop/views/components/ui.header.notifications.vue
index c59a49556..fa3be7909 100644
--- a/src/client/app/desktop/views/components/ui.header.notifications.vue
+++ b/src/client/app/desktop/views/components/ui.header.notifications.vue
@@ -1,7 +1,8 @@
 <template>
 <div class="notifications" v-hotkey.global="keymap">
 	<button :data-active="isOpen" @click="toggle" title="%i18n:@title%">
-		%fa:R bell%<template v-if="hasUnreadNotification">%fa:circle%</template>
+		<i class="bell"><fa :icon="['far', 'bell']"/></i>
+		<i class="circle" v-if="hasUnreadNotification"><fa icon="circle"/></i>
 	</button>
 	<div class="pop" v-if="isOpen">
 		<mk-notifications/>
@@ -79,11 +80,11 @@ export default Vue.extend({
 		&[data-active='true']
 			color var(--desktopHeaderHoverFg)
 
-		> [data-fa].bell
+		> i.bell
 			font-size 1.2em
 			line-height 48px
 
-		> [data-fa].circle
+		> i.circle
 			margin-left -5px
 			vertical-align super
 			font-size 10px
diff --git a/src/client/app/desktop/views/components/ui.header.post.vue b/src/client/app/desktop/views/components/ui.header.post.vue
index a0d8cbdf8..2955b3348 100644
--- a/src/client/app/desktop/views/components/ui.header.post.vue
+++ b/src/client/app/desktop/views/components/ui.header.post.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="note">
-	<button @click="post" title="%i18n:@post%">%fa:pencil-alt%</button>
+	<button @click="post" title="%i18n:@post%"><fa icon="pencil-alt"/></button>
 </div>
 </template>
 
diff --git a/src/client/app/desktop/views/components/ui.header.search.vue b/src/client/app/desktop/views/components/ui.header.search.vue
index 0880f4b72..eb08751eb 100644
--- a/src/client/app/desktop/views/components/ui.header.search.vue
+++ b/src/client/app/desktop/views/components/ui.header.search.vue
@@ -1,6 +1,6 @@
 <template>
 <form class="search" @submit.prevent="onSubmit">
-	%fa:search%
+	<i><fa icon="search"/></i>
 	<input v-model="q" type="search" placeholder="%i18n:@placeholder%"/>
 	<div class="result"></div>
 </form>
@@ -32,7 +32,7 @@ export default Vue.extend({
 	@media (max-width 800px)
 		display none !important
 
-	> [data-fa]
+	> i
 		display block
 		position absolute
 		top 0
diff --git a/src/client/app/desktop/views/components/ui.sidebar.vue b/src/client/app/desktop/views/components/ui.sidebar.vue
index 36b5b3958..7c68074be 100644
--- a/src/client/app/desktop/views/components/ui.sidebar.vue
+++ b/src/client/app/desktop/views/components/ui.sidebar.vue
@@ -2,43 +2,43 @@
 <div class="header" :class="navbar">
 	<div class="body">
 		<div class="post">
-			<button @click="post" title="%i18n:@post%">%fa:pencil-alt%</button>
+			<button @click="post" title="%i18n:@post%"><fa icon="pencil-alt"/></button>
 		</div>
 
 		<div class="nav" v-if="$store.getters.isSignedIn">
 			<template v-if="$store.state.device.deckDefault">
 				<div class="deck" :class="{ active: $route.name == 'deck' || $route.name == 'index' }" @click="goToTop">
-					<router-link to="/">%fa:columns%</router-link>
+					<router-link to="/"><fa icon="columns"/></router-link>
 				</div>
 				<div class="home" :class="{ active: $route.name == 'home' }" @click="goToTop">
-					<router-link to="/home">%fa:home%</router-link>
+					<router-link to="/home"><fa icon="home"/></router-link>
 				</div>
 			</template>
 			<template v-else>
 				<div class="home" :class="{ active: $route.name == 'home' || $route.name == 'index' }" @click="goToTop">
-					<router-link to="/">%fa:home%</router-link>
+					<router-link to="/"><fa icon="home"/></router-link>
 				</div>
 				<div class="deck" :class="{ active: $route.name == 'deck' }" @click="goToTop">
-					<router-link to="/deck">%fa:columns%</router-link>
+					<router-link to="/deck"><fa icon="columns"/></router-link>
 				</div>
 			</template>
 			<div class="messaging">
-				<a @click="messaging">%fa:comments%<template v-if="hasUnreadMessagingMessage">%fa:circle%</template></a>
+				<a @click="messaging"><fa icon="comments"/><template v-if="hasUnreadMessagingMessage"><fa icon="circle"/></template></a>
 			</div>
 			<div class="game">
-				<a @click="game">%fa:gamepad%<template v-if="hasGameInvitations">%fa:circle%</template></a>
+				<a @click="game"><fa icon="gamepad"/><template v-if="hasGameInvitations"><fa icon="circle"/></template></a>
 			</div>
 		</div>
 
 		<div class="nav bottom" v-if="$store.getters.isSignedIn">
 			<div>
-				<a @click="drive">%fa:cloud%</a>
+				<a @click="drive"><fa icon="cloud"/></a>
 			</div>
 			<div ref="notificationsButton" :class="{ active: showNotifications }">
-				<a @click="notifications">%fa:R bell%</a>
+				<a @click="notifications"><fa :icon="['far', 'bell']"/></a>
 			</div>
 			<div>
-				<a @click="settings">%fa:cog%</a>
+				<a @click="settings"><fa icon="cog"/></a>
 			</div>
 		</div>
 
@@ -49,20 +49,20 @@
 
 			<div class="nav menu">
 				<div class="signout">
-					<a @click="signout">%fa:power-off%</a>
+					<a @click="signout"><fa icon="power-off"/></a>
 				</div>
 				<div>
-					<router-link to="/i/favorites">%fa:star%</router-link>
+					<router-link to="/i/favorites"><fa icon="star"/></router-link>
 				</div>
 				<div v-if="($store.state.i.isLocked || $store.state.i.carefulBot)">
-					<a @click="followRequests">%fa:envelope R%<i v-if="$store.state.i.pendingReceivedFollowRequestsCount">{{ $store.state.i.pendingReceivedFollowRequestsCount }}</i></a>
+					<a @click="followRequests"><fa :icon="['far', 'envelope']"/><i v-if="$store.state.i.pendingReceivedFollowRequestsCount">{{ $store.state.i.pendingReceivedFollowRequestsCount }}</i></a>
 				</div>
 			</div>
 		</div>
 
 		<div class="nav dark">
 			<div>
-				<a @click="dark"><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template></a>
+				<a @click="dark"><template v-if="$store.state.device.darkmode"><fa icon="moon"/></template><template v-else><fa :icon="['far', 'moon']"/></template></a>
 			</div>
 		</div>
 	</div>
diff --git a/src/client/app/desktop/views/components/user-lists-window.vue b/src/client/app/desktop/views/components/user-lists-window.vue
index 9c384314c..594337920 100644
--- a/src/client/app/desktop/views/components/user-lists-window.vue
+++ b/src/client/app/desktop/views/components/user-lists-window.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-window ref="window" is-modal width="450px" height="500px" @closed="destroyDom">
-	<span slot="header">%fa:list% %i18n:@title%</span>
+	<span slot="header"><fa icon="list"/> %i18n:@title%</span>
 
 	<div class="xkxvokkjlptzyewouewmceqcxhpgzprp">
 		<button class="ui" @click="add">%i18n:@create-list%</button>
diff --git a/src/client/app/desktop/views/components/users-list.vue b/src/client/app/desktop/views/components/users-list.vue
index 1316f277b..05fe6c292 100644
--- a/src/client/app/desktop/views/components/users-list.vue
+++ b/src/client/app/desktop/views/components/users-list.vue
@@ -18,7 +18,7 @@
 	<p class="no" v-if="!fetching && users.length == 0">
 		<slot></slot>
 	</p>
-	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@fetching%<mk-ellipsis/></p>
+	<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:@fetching%<mk-ellipsis/></p>
 </div>
 </template>
 
@@ -139,7 +139,7 @@ export default Vue.extend({
 		text-align center
 		color #aaa
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 
 </style>
diff --git a/src/client/app/desktop/views/components/widget-container.vue b/src/client/app/desktop/views/components/widget-container.vue
index a50635703..c14f5f551 100644
--- a/src/client/app/desktop/views/components/widget-container.vue
+++ b/src/client/app/desktop/views/components/widget-container.vue
@@ -48,7 +48,7 @@ export default Vue.extend({
 			color var(--faceHeaderText)
 			box-shadow 0 1px rgba(#000, 0.07)
 
-			> [data-fa]
+			> [data-icon]
 				margin-right 6px
 
 			&:empty
diff --git a/src/client/app/desktop/views/components/window.vue b/src/client/app/desktop/views/components/window.vue
index a1893ffd6..6668e0025 100644
--- a/src/client/app/desktop/views/components/window.vue
+++ b/src/client/app/desktop/views/components/window.vue
@@ -8,8 +8,12 @@
 			>
 				<h1><slot name="header"></slot></h1>
 				<div>
-					<button class="popout" v-if="popoutUrl" @mousedown.stop="() => {}" @click="popout" title="%i18n:@popout%">%fa:R window-restore%</button>
-					<button class="close" v-if="canClose" @mousedown.stop="() => {}" @click="close" title="%i18n:@close%">%fa:times%</button>
+					<button class="popout" v-if="popoutUrl" @mousedown.stop="() => {}" @click="popout" title="%i18n:@popout%">
+						<i><fa :icon="['far', 'window-restore']"/></i>
+					</button>
+					<button class="close" v-if="canClose" @mousedown.stop="() => {}" @click="close" title="%i18n:@close%">
+						<i><fa icon="times"/></i>
+					</button>
 				</div>
 			</header>
 			<div class="content">
@@ -612,7 +616,8 @@ export default Vue.extend({
 						&:active
 							color var(--faceTextButtonActive)
 
-						> [data-fa]
+						> i
+							display inline-block
 							padding 0
 							width $header-height
 							line-height $header-height
diff --git a/src/client/app/desktop/views/pages/deck/deck.column.vue b/src/client/app/desktop/views/pages/deck/deck.column.vue
index 00b2453f9..ac811ce7c 100644
--- a/src/client/app/desktop/views/pages/deck/deck.column.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.column.vue
@@ -11,13 +11,13 @@
 			@dragend="onDragend"
 			@contextmenu.prevent.stop="onContextmenu">
 		<button class="toggleActive" @click="toggleActive" v-if="isStacked">
-			<template v-if="active">%fa:angle-up%</template>
-			<template v-else>%fa:angle-down%</template>
+			<template v-if="active"><fa icon="angle-up"/></template>
+			<template v-else><fa icon="angle-down"/></template>
 		</button>
 		<slot name="header"></slot>
 		<span class="count" v-if="count > 0">({{ count }})</span>
-		<button v-if="!isTemporaryColumn" class="menu" ref="menu" @click.stop="showMenu">%fa:caret-down%</button>
-		<button v-else class="close" @click.stop="close">%fa:times%</button>
+		<button v-if="!isTemporaryColumn" class="menu" ref="menu" @click.stop="showMenu"><fa icon="caret-down"/></button>
+		<button v-else class="close" @click.stop="close"><fa icon="times"/></button>
 	</header>
 	<div ref="body" v-show="active">
 		<slot></slot>
@@ -163,7 +163,7 @@ export default Vue.extend({
 
 		getMenu() {
 			const items = [{
-				icon: '%fa:pencil-alt%',
+				icon: 'pencil-alt',
 				text: '%i18n:common.deck.rename%',
 				action: () => {
 					(this as any).apis.input({
@@ -175,43 +175,43 @@ export default Vue.extend({
 					});
 				}
 			}, null, {
-				icon: '%fa:arrow-left%',
+				icon: 'arrow-left',
 				text: '%i18n:common.deck.swap-left%',
 				action: () => {
 					this.$store.dispatch('settings/swapLeftDeckColumn', this.column.id);
 				}
 			}, {
-				icon: '%fa:arrow-right%',
+				icon: 'arrow-right',
 				text: '%i18n:common.deck.swap-right%',
 				action: () => {
 					this.$store.dispatch('settings/swapRightDeckColumn', this.column.id);
 				}
 			}, this.isStacked ? {
-				icon: '%fa:arrow-up%',
+				icon: 'arrow-up',
 				text: '%i18n:common.deck.swap-up%',
 				action: () => {
 					this.$store.dispatch('settings/swapUpDeckColumn', this.column.id);
 				}
 			} : undefined, this.isStacked ? {
-				icon: '%fa:arrow-down%',
+				icon: 'arrow-down',
 				text: '%i18n:common.deck.swap-down%',
 				action: () => {
 					this.$store.dispatch('settings/swapDownDeckColumn', this.column.id);
 				}
 			} : undefined, null, {
-				icon: '%fa:window-restore R%',
+				icon: ['far', 'window-restore'],
 				text: '%i18n:common.deck.stack-left%',
 				action: () => {
 					this.$store.dispatch('settings/stackLeftDeckColumn', this.column.id);
 				}
 			}, this.isStacked ? {
-				icon: '%fa:window-maximize R%',
+				icon: ['far', 'window-maximize'],
 				text: '%i18n:common.deck.pop-right%',
 				action: () => {
 					this.$store.dispatch('settings/popRightDeckColumn', this.column.id);
 				}
 			} : undefined, null, {
-				icon: '%fa:trash-alt R%',
+				icon: ['far', 'trash-alt'],
 				text: '%i18n:common.deck.remove%',
 				action: () => {
 					this.$store.dispatch('settings/removeDeckColumn', this.column.id);
@@ -382,7 +382,7 @@ export default Vue.extend({
 			box-shadow 0 3px 0 0 var(--primary)
 
 		> span
-			[data-fa]
+			[data-icon]
 				margin-right 8px
 
 		> .count
diff --git a/src/client/app/desktop/views/pages/deck/deck.direct-column.vue b/src/client/app/desktop/views/pages/deck/deck.direct-column.vue
index 7744a755e..baee7ff5e 100644
--- a/src/client/app/desktop/views/pages/deck/deck.direct-column.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.direct-column.vue
@@ -1,6 +1,6 @@
 <template>
 <x-column :name="name" :column="column" :is-stacked="isStacked">
-	<span slot="header">%fa:envelope R%{{ name }}</span>
+	<span slot="header"><fa :icon="['far', 'envelope']"/>{{ name }}</span>
 
 	<x-direct/>
 </x-column>
diff --git a/src/client/app/desktop/views/pages/deck/deck.hashtag-column.vue b/src/client/app/desktop/views/pages/deck/deck.hashtag-column.vue
index 2b5bf14b2..a6d09e60c 100644
--- a/src/client/app/desktop/views/pages/deck/deck.hashtag-column.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.hashtag-column.vue
@@ -1,7 +1,7 @@
 <template>
 <x-column>
 	<span slot="header">
-		%fa:hashtag%<span>{{ tag }}</span>
+		<fa icon="hashtag"/><span>{{ tag }}</span>
 	</span>
 
 	<div class="xroyrflcmhhtmlwmyiwpfqiirqokfueb">
diff --git a/src/client/app/desktop/views/pages/deck/deck.mentions-column.vue b/src/client/app/desktop/views/pages/deck/deck.mentions-column.vue
index 6598832ba..19537a2db 100644
--- a/src/client/app/desktop/views/pages/deck/deck.mentions-column.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.mentions-column.vue
@@ -1,6 +1,6 @@
 <template>
 <x-column :name="name" :column="column" :is-stacked="isStacked">
-	<span slot="header">%fa:at%{{ name }}</span>
+	<span slot="header"><fa icon="at"/>{{ name }}</span>
 
 	<x-mentions ref="tl"/>
 </x-column>
diff --git a/src/client/app/desktop/views/pages/deck/deck.note-column.vue b/src/client/app/desktop/views/pages/deck/deck.note-column.vue
index 8335c37bf..dae6debe7 100644
--- a/src/client/app/desktop/views/pages/deck/deck.note-column.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.note-column.vue
@@ -1,13 +1,13 @@
 <template>
 <x-column>
 	<span slot="header">
-		%fa:comment-alt R%<span>{{ title }}</span>
+		<fa :icon="['far', 'comment-alt']"/><span>{{ title }}</span>
 	</span>
 
 	<div class="rvtscbadixhhbsczoorqoaygovdeecsx" v-if="note">
 		<div class="is-remote" v-if="note.user.host != null">
 			<details>
-				<summary>%fa:exclamation-triangle% %i18n:common.is-remote-post%</summary>
+				<summary><fa icon="exclamation-triangle"/> %i18n:common.is-remote-post%</summary>
 				<a :href="note.url || note.uri" target="_blank">%i18n:common.view-on-remote%</a>
 			</details>
 		</div>
diff --git a/src/client/app/desktop/views/pages/deck/deck.notes.vue b/src/client/app/desktop/views/pages/deck/deck.notes.vue
index a5f20df5b..b7a47ddb2 100644
--- a/src/client/app/desktop/views/pages/deck/deck.notes.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.notes.vue
@@ -21,8 +21,8 @@
 				:media-view="mediaView"
 				:mini="true"/>
 			<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
-				<span>%fa:angle-up%{{ note._datetext }}</span>
-				<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
+				<span><fa icon="angle-up"/>{{ note._datetext }}</span>
+				<span><fa icon="angle-down"/>{{ _notes[i + 1]._datetext }}</span>
 			</p>
 		</template>
 	</div>
@@ -31,7 +31,7 @@
 	<footer v-if="more">
 		<button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
 			<template v-if="!moreFetching">%i18n:@load-more%</template>
-			<template v-if="moreFetching">%fa:spinner .pulse .fw%</template>
+			<template v-if="moreFetching"><fa icon="spinner .pulse" fixed-width/></template>
 		</button>
 	</footer>
 </div>
@@ -236,7 +236,7 @@ export default Vue.extend({
 			span
 				margin 0 16px
 
-			[data-fa]
+			[data-icon]
 				margin-right 8px
 
 	> footer
diff --git a/src/client/app/desktop/views/pages/deck/deck.notification.vue b/src/client/app/desktop/views/pages/deck/deck.notification.vue
index fa8f99a2b..f1b482f3a 100644
--- a/src/client/app/desktop/views/pages/deck/deck.notification.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.notification.vue
@@ -9,8 +9,8 @@
 				<mk-time :time="notification.createdAt"/>
 			</header>
 			<router-link class="note-ref" :to="notification.note | notePage">
-				%fa:quote-left%{{ getNoteSummary(notification.note) }}
-				%fa:quote-right%
+				<fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}
+				<fa icon="quote-right"/>
 			</router-link>
 		</div>
 	</div>
@@ -19,12 +19,12 @@
 		<mk-avatar class="avatar" :user="notification.user"/>
 		<div>
 			<header>
-				%fa:retweet%
+				<fa icon="retweet"/>
 				<router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link>
 				<mk-time :time="notification.createdAt"/>
 			</header>
 			<router-link class="note-ref" :to="notification.note | notePage">
-				%fa:quote-left%{{ getNoteSummary(notification.note.renote) }}%fa:quote-right%
+				<fa icon="quote-left"/>{{ getNoteSummary(notification.note.renote) }}<fa icon="quote-right"/>
 			</router-link>
 		</div>
 	</div>
@@ -33,7 +33,7 @@
 		<mk-avatar class="avatar" :user="notification.user"/>
 		<div>
 			<header>
-				%fa:user-plus%
+				<fa icon="user-plus"/>
 				<router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link>
 				<mk-time :time="notification.createdAt"/>
 			</header>
@@ -44,7 +44,7 @@
 		<mk-avatar class="avatar" :user="notification.user"/>
 		<div>
 			<header>
-				%fa:user-clock%
+				<fa icon="user-clock"/>
 				<router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link>
 				<mk-time :time="notification.createdAt"/>
 			</header>
@@ -55,12 +55,12 @@
 		<mk-avatar class="avatar" :user="notification.user"/>
 		<div>
 			<header>
-				%fa:chart-pie%
+				<fa icon="chart-pie"/>
 				<router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link>
 				<mk-time :time="notification.createdAt"/>
 			</header>
 			<router-link class="note-ref" :to="notification.note | notePage">
-				%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%
+				<fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}<fa icon="quote-right"/>
 			</router-link>
 		</div>
 	</div>
@@ -151,7 +151,7 @@ export default Vue.extend({
 			> .note-ref
 				color var(--noteText)
 
-				[data-fa]
+				[data-icon]
 					font-size 1em
 					font-weight normal
 					font-style normal
diff --git a/src/client/app/desktop/views/pages/deck/deck.notifications-column.vue b/src/client/app/desktop/views/pages/deck/deck.notifications-column.vue
index 220e938a4..5ecc41d69 100644
--- a/src/client/app/desktop/views/pages/deck/deck.notifications-column.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.notifications-column.vue
@@ -1,6 +1,6 @@
 <template>
 <x-column :name="name" :column="column" :is-stacked="isStacked">
-	<span slot="header">%fa:bell R%{{ name }}</span>
+	<span slot="header"><fa :icon="['far', 'bell']"/>{{ name }}</span>
 
 	<x-notifications/>
 </x-column>
diff --git a/src/client/app/desktop/views/pages/deck/deck.notifications.vue b/src/client/app/desktop/views/pages/deck/deck.notifications.vue
index 59d361b0b..168ecc14f 100644
--- a/src/client/app/desktop/views/pages/deck/deck.notifications.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.notifications.vue
@@ -11,13 +11,13 @@
 		<template v-for="(notification, i) in _notifications">
 			<x-notification class="notification" :notification="notification" :key="notification.id"/>
 			<p class="date" v-if="i != notifications.length - 1 && notification._date != _notifications[i + 1]._date" :key="notification.id + '-time'">
-				<span>%fa:angle-up%{{ notification._datetext }}</span>
-				<span>%fa:angle-down%{{ _notifications[i + 1]._datetext }}</span>
+				<span><fa icon="angle-up"/>{{ notification._datetext }}</span>
+				<span><fa icon="angle-down"/>{{ _notifications[i + 1]._datetext }}</span>
 			</p>
 		</template>
 	</component>
 	<button class="more" :class="{ fetching: fetchingMoreNotifications }" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications">
-		<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
+		<template v-if="fetchingMoreNotifications"><fa icon="spinner .pulse" fixed-width/></template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
 	</button>
 	<p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:@empty%</p>
 </div>
@@ -188,7 +188,7 @@ export default Vue.extend({
 			span
 				margin 0 16px
 
-			i
+			[data-icon]
 				margin-right 8px
 
 	> .more
@@ -207,7 +207,7 @@ export default Vue.extend({
 		&.fetching
 			cursor wait
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 
 	> .empty
diff --git a/src/client/app/desktop/views/pages/deck/deck.tl-column.vue b/src/client/app/desktop/views/pages/deck/deck.tl-column.vue
index 6faef3643..44ef4eda1 100644
--- a/src/client/app/desktop/views/pages/deck/deck.tl-column.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.tl-column.vue
@@ -1,12 +1,12 @@
 <template>
 <x-column :menu="menu" :name="name" :column="column" :is-stacked="isStacked">
 	<span slot="header">
-		<template v-if="column.type == 'home'">%fa:home%</template>
-		<template v-if="column.type == 'local'">%fa:R comments%</template>
-		<template v-if="column.type == 'hybrid'">%fa:share-alt%</template>
-		<template v-if="column.type == 'global'">%fa:globe%</template>
-		<template v-if="column.type == 'list'">%fa:list%</template>
-		<template v-if="column.type == 'hashtag'">%fa:hashtag%</template>
+		<template v-if="column.type == 'home'"><fa icon="home"/></template>
+		<template v-if="column.type == 'local'"><fa :icon="['far', 'comments']"/></template>
+		<template v-if="column.type == 'hybrid'"><fa icon="share-alt"/></template>
+		<template v-if="column.type == 'global'"><fa icon="globe"/></template>
+		<template v-if="column.type == 'list'"><fa icon="list"/></template>
+		<template v-if="column.type == 'hashtag'"><fa icon="hashtag"/></template>
 		<span>{{ name }}</span>
 	</span>
 
@@ -66,7 +66,7 @@ export default Vue.extend({
 		return {
 			edit: false,
 			menu: [{
-				icon: '%fa:cog%',
+				icon: 'cog',
 				text: '%i18n:@edit%',
 				action: () => {
 					this.edit = !this.edit;
diff --git a/src/client/app/desktop/views/pages/deck/deck.user-column.vue b/src/client/app/desktop/views/pages/deck/deck.user-column.vue
index 7a84f6605..8bd542171 100644
--- a/src/client/app/desktop/views/pages/deck/deck.user-column.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.user-column.vue
@@ -1,19 +1,19 @@
 <template>
 <x-column>
 	<span slot="header">
-		%fa:user%<span>{{ title }}</span>
+		<fa icon="user"/><span>{{ title }}</span>
 	</span>
 
 	<div class="zubukjlciycdsyynicqrnlsmdwmymzqu" v-if="user">
 		<div class="is-remote" v-if="user.host != null">
 			<details>
-				<summary>%fa:exclamation-triangle% %i18n:common.is-remote-user%</summary>
+				<summary><fa icon="exclamation-triangle"/> %i18n:common.is-remote-user%</summary>
 				<a :href="user.url || user.uri" target="_blank">%i18n:common.view-on-remote%</a>
 			</details>
 		</div>
 		<header :style="bannerStyle">
 			<div>
-				<button class="menu" @click="menu" ref="menu">%fa:ellipsis-h%</button>
+				<button class="menu" @click="menu" ref="menu"><fa icon="ellipsis-h"/></button>
 				<mk-follow-button v-if="$store.getters.isSignedIn && user.id != $store.state.i.id" :user="user" class="follow"/>
 				<mk-avatar class="avatar" :user="user" :disable-preview="true"/>
 				<span class="name">{{ user | userName }}</span>
@@ -40,17 +40,17 @@
 			</div>
 		</div>
 		<div class="pinned" v-if="user.pinnedNotes && user.pinnedNotes.length > 0">
-			<p class="caption" @click="toggleShowPinned">%fa:thumbtack% %i18n:@pinned-notes%</p>
-			<span class="angle" v-if="showPinned">%fa:angle-up%</span>
-			<span class="angle" v-else>%fa:angle-down%</span>
+			<p class="caption" @click="toggleShowPinned"><fa icon="thumbtack"/> %i18n:@pinned-notes%</p>
+			<span class="angle" v-if="showPinned"><fa icon="angle-up"/></span>
+			<span class="angle" v-else><fa icon="angle-down"/></span>
 			<div class="notes" v-show="showPinned">
 				<x-note v-for="n in user.pinnedNotes" :key="n.id" :note="n" :mini="true"/>
 			</div>
 		</div>
 		<div class="images" v-if="images.length > 0">
-			<p class="caption" @click="toggleShowImages">%fa:images R% %i18n:@images%</p>
-			<span class="angle" v-if="showImages">%fa:angle-up%</span>
-			<span class="angle" v-else>%fa:angle-down%</span>
+			<p class="caption" @click="toggleShowImages"><fa :icon="['far', 'images']"/> %i18n:@images%</p>
+			<span class="angle" v-if="showImages"><fa icon="angle-up"/></span>
+			<span class="angle" v-else><fa icon="angle-down"/></span>
 			<div v-show="showImages">
 				<router-link v-for="image in images"
 					:style="`background-image: url(${image.thumbnailUrl})`"
@@ -61,15 +61,15 @@
 			</div>
 		</div>
 		<div class="activity">
-			<p class="caption" @click="toggleShowActivity">%fa:chart-bar R% %i18n:@activity%</p>
-			<span class="angle" v-if="showActivity">%fa:angle-up%</span>
-			<span class="angle" v-else>%fa:angle-down%</span>
+			<p class="caption" @click="toggleShowActivity"><fa :icon="['far', 'chart-bar']"/> %i18n:@activity%</p>
+			<span class="angle" v-if="showActivity"><fa icon="angle-up"/></span>
+			<span class="angle" v-else><fa icon="angle-down"/></span>
 			<div v-show="showActivity">
 				<div ref="chart"></div>
 			</div>
 		</div>
 		<div class="tl">
-			<p class="caption">%fa:comment-alt R% %i18n:@timeline%</p>
+			<p class="caption"><fa :icon="['far', 'comment-alt']"/> %i18n:@timeline%</p>
 			<div>
 				<x-notes ref="timeline" :more="existMore ? fetchMoreNotes : null"/>
 			</div>
@@ -294,7 +294,7 @@ export default Vue.extend({
 
 		menu() {
 			let menu = [{
-				icon: '%fa:list%',
+				icon: 'list',
 				text: '%i18n:@push-to-a-list%',
 				action: () => {
 					const w = (this as any).os.new(MkUserListsWindow);
diff --git a/src/client/app/desktop/views/pages/deck/deck.vue b/src/client/app/desktop/views/pages/deck/deck.vue
index 3b3102bd7..e1b9e7681 100644
--- a/src/client/app/desktop/views/pages/deck/deck.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.vue
@@ -14,7 +14,7 @@
 			<x-note-column v-else-if="temporaryColumn.type == 'note'" :note-id="temporaryColumn.noteId" :key="temporaryColumn.noteId"/>
 			<x-hashtag-column v-else-if="temporaryColumn.type == 'tag'" :tag="temporaryColumn.tag" :key="temporaryColumn.tag"/>
 		</template>
-		<button ref="add" @click="add" title="%i18n:common.deck.add-column%">%fa:plus%</button>
+		<button ref="add" @click="add" title="%i18n:common.deck.add-column%"><fa icon="plus"/></button>
 	</div>
 </mk-ui>
 </template>
@@ -182,7 +182,7 @@ export default Vue.extend({
 				source: this.$refs.add,
 				compact: true,
 				items: [{
-					icon: '%fa:home%',
+					icon: 'home',
 					text: '%i18n:common.deck.home%',
 					action: () => {
 						this.$store.dispatch('settings/addDeckColumn', {
@@ -191,7 +191,7 @@ export default Vue.extend({
 						});
 					}
 				}, {
-					icon: '%fa:comments R%',
+					icon: ['far', 'comments'],
 					text: '%i18n:common.deck.local%',
 					action: () => {
 						this.$store.dispatch('settings/addDeckColumn', {
@@ -200,7 +200,7 @@ export default Vue.extend({
 						});
 					}
 				}, {
-					icon: '%fa:share-alt%',
+					icon: 'share-alt',
 					text: '%i18n:common.deck.hybrid%',
 					action: () => {
 						this.$store.dispatch('settings/addDeckColumn', {
@@ -209,7 +209,7 @@ export default Vue.extend({
 						});
 					}
 				}, {
-					icon: '%fa:globe%',
+					icon: 'globe',
 					text: '%i18n:common.deck.global%',
 					action: () => {
 						this.$store.dispatch('settings/addDeckColumn', {
@@ -218,7 +218,7 @@ export default Vue.extend({
 						});
 					}
 				}, {
-					icon: '%fa:at%',
+					icon: 'at',
 					text: '%i18n:common.deck.mentions%',
 					action: () => {
 						this.$store.dispatch('settings/addDeckColumn', {
@@ -227,7 +227,7 @@ export default Vue.extend({
 						});
 					}
 				}, {
-					icon: '%fa:envelope R%',
+					icon: ['far', 'envelope'],
 					text: '%i18n:common.deck.direct%',
 					action: () => {
 						this.$store.dispatch('settings/addDeckColumn', {
@@ -236,7 +236,7 @@ export default Vue.extend({
 						});
 					}
 				}, {
-					icon: '%fa:list%',
+					icon: 'list',
 					text: '%i18n:common.deck.list%',
 					action: () => {
 						const w = (this as any).os.new(MkUserListsWindow);
@@ -250,7 +250,7 @@ export default Vue.extend({
 						});
 					}
 				}, {
-					icon: '%fa:hashtag%',
+					icon: 'hashtag',
 					text: '%i18n:common.deck.hashtag%',
 					action: () => {
 						(this as any).apis.input({
@@ -264,7 +264,7 @@ export default Vue.extend({
 						});
 					}
 				}, {
-					icon: '%fa:bell R%',
+					icon: ['far', 'bell'],
 					text: '%i18n:common.deck.notifications%',
 					action: () => {
 						this.$store.dispatch('settings/addDeckColumn', {
@@ -273,7 +273,7 @@ export default Vue.extend({
 						});
 					}
 				}, {
-					icon: '%fa:calculator%',
+					icon: 'calculator',
 					text: '%i18n:common.deck.widgets%',
 					action: () => {
 						this.$store.dispatch('settings/addDeckColumn', {
diff --git a/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue b/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue
index e1fecc98b..34b2af7d1 100644
--- a/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue
@@ -1,6 +1,6 @@
 <template>
 <x-column :menu="menu" :naked="true" :narrow="true" :name="name" :column="column" :is-stacked="isStacked" class="wtdtxvecapixsepjtcupubtsmometobz">
-	<span slot="header">%fa:calculator%{{ name }}</span>
+	<span slot="header"><fa icon="calculator"/>{{ name }}</span>
 
 	<div class="gqpwvtwtprsbmnssnbicggtwqhmylhnq">
 		<template v-if="edit">
@@ -37,7 +37,7 @@
 				@sort="onWidgetSort"
 			>
 				<div v-for="widget in column.widgets" class="customize-container" :key="widget.id" @contextmenu.stop.prevent="widgetFunc(widget.id)">
-					<button class="remove" @click="removeWidget(widget)">%fa:times%</button>
+					<button class="remove" @click="removeWidget(widget)"><fa icon="times"/></button>
 					<component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-customize-mode="true" platform="deck"/>
 				</div>
 			</x-draggable>
@@ -89,7 +89,7 @@ export default Vue.extend({
 
 	created() {
 		this.menu = [{
-			icon: '%fa:cog%',
+			icon: 'cog',
 			text: '%i18n:@edit%',
 			action: () => {
 				this.edit = !this.edit;
diff --git a/src/client/app/desktop/views/pages/note.vue b/src/client/app/desktop/views/pages/note.vue
index 8502dd3d5..1e53b97cf 100644
--- a/src/client/app/desktop/views/pages/note.vue
+++ b/src/client/app/desktop/views/pages/note.vue
@@ -3,8 +3,8 @@
 	<main v-if="!fetching">
 		<mk-note-detail :note="note"/>
 		<footer>
-			<router-link v-if="note.next" :to="note.next">%fa:angle-left% %i18n:@next%</router-link>
-			<router-link v-if="note.prev" :to="note.prev">%i18n:@prev% %fa:angle-right%</router-link>
+			<router-link v-if="note.next" :to="note.next"><fa icon="angle-left"/> %i18n:@next%</router-link>
+			<router-link v-if="note.prev" :to="note.prev">%i18n:@prev% <fa icon="angle-right"/></router-link>
 		</footer>
 	</main>
 </mk-ui>
diff --git a/src/client/app/desktop/views/pages/search.vue b/src/client/app/desktop/views/pages/search.vue
index f088ba114..25046531e 100644
--- a/src/client/app/desktop/views/pages/search.vue
+++ b/src/client/app/desktop/views/pages/search.vue
@@ -4,7 +4,7 @@
 		<h1>{{ q }}</h1>
 	</header>
 	<p :class="$style.notAvailable" v-if="!fetching && notAvailable">%i18n:@not-available%</p>
-	<p :class="$style.empty" v-if="!fetching && empty">%fa:search% {{ '%i18n:not-found%'.split('{}')[0] }}{{ q }}{{ '%i18n:not-found%'.split('{}')[1] }}</p>
+	<p :class="$style.empty" v-if="!fetching && empty"><fa icon="search"/> {{ '%i18n:not-found%'.split('{}')[0] }}{{ q }}{{ '%i18n:not-found%'.split('{}')[1] }}</p>
 	<mk-notes ref="timeline" :class="$style.notes" :more="existMore ? more : null"/>
 </mk-ui>
 </template>
@@ -124,13 +124,12 @@ export default Vue.extend({
 	text-align center
 	color #999
 
-	> [data-fa]
+	> [data-icon]
 		display block
 		margin-bottom 16px
 		font-size 3em
 		color #ccc
 
-
 .notAvailable
 	display block
 	margin 0 auto
@@ -139,7 +138,7 @@ export default Vue.extend({
 	text-align center
 	color #999
 
-	> [data-fa]
+	> [data-icon]
 		display block
 		margin-bottom 16px
 		font-size 3em
diff --git a/src/client/app/desktop/views/pages/selectdrive.vue b/src/client/app/desktop/views/pages/selectdrive.vue
index b82ed0a20..64be867a0 100644
--- a/src/client/app/desktop/views/pages/selectdrive.vue
+++ b/src/client/app/desktop/views/pages/selectdrive.vue
@@ -6,7 +6,7 @@
 		@change-selection="onChangeSelection"
 	/>
 	<footer>
-		<button class="upload" title="%i18n:@upload%" @click="upload">%fa:upload%</button>
+		<button class="upload" title="%i18n:@upload%" @click="upload"><fa icon="upload"/></button>
 		<button class="cancel" @click="close">%i18n:@cancel%</button>
 		<button class="ok" @click="ok">%i18n:@ok%</button>
 	</footer>
diff --git a/src/client/app/desktop/views/pages/share.vue b/src/client/app/desktop/views/pages/share.vue
index 69ecbf115..d5e38fed4 100644
--- a/src/client/app/desktop/views/pages/share.vue
+++ b/src/client/app/desktop/views/pages/share.vue
@@ -4,7 +4,7 @@
 	<div>
 		<mk-signin v-if="!$store.getters.isSignedIn"/>
 		<mk-post-form v-else-if="!posted" :initial-text="text" :instant="true" @posted="posted = true"/>
-		<p v-if="posted" class="posted">%fa:check%</p>
+		<p v-if="posted" class="posted"><fa icon="check"/></p>
 	</div>
 	<button v-if="posted" class="ui button" @click="close">%i18n:common.close%</button>
 </div>
diff --git a/src/client/app/desktop/views/pages/tag.vue b/src/client/app/desktop/views/pages/tag.vue
index 5305b4ac1..f72c629ef 100644
--- a/src/client/app/desktop/views/pages/tag.vue
+++ b/src/client/app/desktop/views/pages/tag.vue
@@ -3,7 +3,7 @@
 	<header :class="$style.header">
 		<h1>#{{ $route.params.tag }}</h1>
 	</header>
-	<p :class="$style.empty" v-if="!fetching && empty">%fa:search% {{ '%i18n:no-posts-found%'.split('{}')[0] }}{{ q }}{{ '%i18n:no-posts-found%'.split('{}')[1] }}</p>
+	<p :class="$style.empty" v-if="!fetching && empty"><fa icon="search"/> {{ '%i18n:no-posts-found%'.split('{}')[0] }}{{ q }}{{ '%i18n:no-posts-found%'.split('{}')[1] }}</p>
 	<mk-notes ref="timeline" :class="$style.notes" :more="existMore ? more : null"/>
 </mk-ui>
 </template>
@@ -113,7 +113,7 @@ export default Vue.extend({
 	text-align center
 	color #999
 
-	> [data-fa]
+	> [data-icon]
 		display block
 		margin-bottom 16px
 		font-size 3em
diff --git a/src/client/app/desktop/views/pages/user/user.followers-you-know.vue b/src/client/app/desktop/views/pages/user/user.followers-you-know.vue
index cf05006c0..14765450a 100644
--- a/src/client/app/desktop/views/pages/user/user.followers-you-know.vue
+++ b/src/client/app/desktop/views/pages/user/user.followers-you-know.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="vahgrswmbzfdlmomxnqftuueyvwaafth">
-	<p class="title">%fa:users%%i18n:@title%</p>
-	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@loading%<mk-ellipsis/></p>
+	<p class="title"><fa icon="users"/>%i18n:@title%</p>
+	<p class="initializing" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:@loading%<mk-ellipsis/></p>
 	<div v-if="!fetching && users.length > 0">
 	<router-link v-for="user in users" :to="user | userPage" :key="user.id">
 		<img :src="user.avatarUrl" :alt="user | userName" v-user-preview="user.id"/>
diff --git a/src/client/app/desktop/views/pages/user/user.friends.vue b/src/client/app/desktop/views/pages/user/user.friends.vue
index 36ae36024..60bfc3e4f 100644
--- a/src/client/app/desktop/views/pages/user/user.friends.vue
+++ b/src/client/app/desktop/views/pages/user/user.friends.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="hozptpaliadatkehcmcayizwzwwctpbc">
-	<p class="title">%fa:users%%i18n:@title%</p>
-	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@loading%<mk-ellipsis/></p>
+	<p class="title"><fa icon="users"/>%i18n:@title%</p>
+	<p class="initializing" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:@loading%<mk-ellipsis/></p>
 	<template v-if="!fetching && users.length != 0">
 		<div class="user" v-for="friend in users">
 			<mk-avatar class="avatar" :user="friend"/>
diff --git a/src/client/app/desktop/views/pages/user/user.github.vue b/src/client/app/desktop/views/pages/user/user.github.vue
index e9651e5a5..a4cb1dac0 100644
--- a/src/client/app/desktop/views/pages/user/user.github.vue
+++ b/src/client/app/desktop/views/pages/user/user.github.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="aqooishiizumijmihokohinatamihoaz">
-	<span>%fa:B github%<a :href="`https://github.com/${user.github.login}`" target="_blank">@{{ user.github.login }}</a></span>
+	<span><fa :icon="['fab', 'github']"/><a :href="`https://github.com/${user.github.login}`" target="_blank">@{{ user.github.login }}</a></span>
 </div>
 </template>
 
diff --git a/src/client/app/desktop/views/pages/user/user.header.vue b/src/client/app/desktop/views/pages/user/user.header.vue
index 81398b986..4c3094282 100644
--- a/src/client/app/desktop/views/pages/user/user.header.vue
+++ b/src/client/app/desktop/views/pages/user/user.header.vue
@@ -7,7 +7,7 @@
 			<p class="name">{{ user | userName }}</p>
 			<div>
 				<span class="username"><mk-acct :user="user" :detail="true" /></span>
-				<span v-if="user.isBot" title="%i18n:@is-bot%">%fa:robot%</span>
+				<span v-if="user.isBot" title="%i18n:@is-bot%"><fa icon="robot"/></span>
 			</div>
 		</div>
 	</div>
@@ -17,8 +17,8 @@
 			<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
 		</div>
 		<div class="info">
-			<span class="location" v-if="user.host === null && user.profile.location">%fa:map-marker% {{ user.profile.location }}</span>
-			<span class="birthday" v-if="user.host === null && user.profile.birthday">%fa:birthday-cake% {{ user.profile.birthday.replace('-', '%i18n:@year%').replace('-', '%i18n:@month%') + '%i18n:@day%' }} ({{ age }}%i18n:@years-old%)</span>
+			<span class="location" v-if="user.host === null && user.profile.location"><fa icon="map-marker"/> {{ user.profile.location }}</span>
+			<span class="birthday" v-if="user.host === null && user.profile.birthday"><fa icon="birthday-cake"/> {{ user.profile.birthday.replace('-', '%i18n:@year%').replace('-', '%i18n:@month%') + '%i18n:@day%' }} ({{ age }}%i18n:@years-old%)</span>
 		</div>
 		<div class="status">
 			<span class="notes-count"><b>{{ user.notesCount | number }}</b>%i18n:@posts%</span>
diff --git a/src/client/app/desktop/views/pages/user/user.photos.vue b/src/client/app/desktop/views/pages/user/user.photos.vue
index 2f525b003..6608bd505 100644
--- a/src/client/app/desktop/views/pages/user/user.photos.vue
+++ b/src/client/app/desktop/views/pages/user/user.photos.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="dzsuvbsrrrwobdxifudxuefculdfiaxd">
-	<p class="title">%fa:camera%%i18n:@title%</p>
-	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@loading%<mk-ellipsis/></p>
+	<p class="title"><fa icon="camera"/>%i18n:@title%</p>
+	<p class="initializing" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:@loading%<mk-ellipsis/></p>
 	<div class="stream" v-if="!fetching && images.length > 0">
 		<div v-for="image in images" class="img"
 			:style="`background-image: url(${image.thumbnailUrl})`"
diff --git a/src/client/app/desktop/views/pages/user/user.profile.vue b/src/client/app/desktop/views/pages/user/user.profile.vue
index d0d54d273..bde57e5bc 100644
--- a/src/client/app/desktop/views/pages/user/user.profile.vue
+++ b/src/client/app/desktop/views/pages/user/user.profile.vue
@@ -4,20 +4,20 @@
 		<mk-follow-button :user="user" size="big"/>
 		<p class="followed" v-if="user.isFollowed">%i18n:@follows-you%</p>
 		<p class="stalk" v-if="user.isFollowing">
-			<span v-if="user.isStalking">%i18n:@stalking% <a @click="unstalk">%fa:meh% %i18n:@unstalk%</a></span>
-			<span v-if="!user.isStalking"><a @click="stalk">%fa:user-secret% %i18n:@stalk%</a></span>
+			<span v-if="user.isStalking">%i18n:@stalking% <a @click="unstalk"><fa icon="meh"/> %i18n:@unstalk%</a></span>
+			<span v-if="!user.isStalking"><a @click="stalk"><fa icon="user-secret"/> %i18n:@stalk%</a></span>
 		</p>
 	</div>
 	<div class="action-form">
 		<ui-button @click="user.isMuted ? unmute() : mute()" v-if="$store.state.i.id != user.id">
-			<span v-if="user.isMuted">%fa:eye% %i18n:@unmute%</span>
-			<span v-else>%fa:eye-slash% %i18n:@mute%</span>
+			<span v-if="user.isMuted"><fa icon="eye"/> %i18n:@unmute%</span>
+			<span v-else><fa icon="eye-slash"/> %i18n:@mute%</span>
 		</ui-button>
 		<ui-button @click="user.isBlocking ? unblock() : block()" v-if="$store.state.i.id != user.id">
-			<span v-if="user.isBlocking">%fa:user% %i18n:@unblock%</span>
-			<span v-else>%fa:user-slash% %i18n:@block%</span>
+			<span v-if="user.isBlocking"><fa icon="user"/> %i18n:@unblock%</span>
+			<span v-else><fa icon="user-slash"/> %i18n:@block%</span>
 		</ui-button>
-		<ui-button @click="list">%fa:list% %i18n:@push-to-a-list%</ui-button>
+		<ui-button @click="list"><fa icon="list"/> %i18n:@push-to-a-list%</ui-button>
 	</div>
 </div>
 </template>
diff --git a/src/client/app/desktop/views/pages/user/user.timeline.vue b/src/client/app/desktop/views/pages/user/user.timeline.vue
index a8d49c8d6..8df546aad 100644
--- a/src/client/app/desktop/views/pages/user/user.timeline.vue
+++ b/src/client/app/desktop/views/pages/user/user.timeline.vue
@@ -1,12 +1,12 @@
 <template>
 <div class="oh5y2r7l5lx8j6jj791ykeiwgihheguk">
 	<header>
-		<span :data-active="mode == 'default'" @click="mode = 'default'">%fa:comment-alt R% %i18n:@default%</span>
-		<span :data-active="mode == 'with-replies'" @click="mode = 'with-replies'">%fa:comments% %i18n:@with-replies%</span>
-		<span :data-active="mode == 'with-media'" @click="mode = 'with-media'">%fa:images% %i18n:@with-media%</span>
+		<span :data-active="mode == 'default'" @click="mode = 'default'"><fa :icon="['far', 'comment-alt']"/> %i18n:@default%</span>
+		<span :data-active="mode == 'with-replies'" @click="mode = 'with-replies'"><fa icon="comments"/> %i18n:@with-replies%</span>
+		<span :data-active="mode == 'with-media'" @click="mode = 'with-media'"><fa icon="images"/> %i18n:@with-media%</span>
 	</header>
 	<mk-notes ref="timeline" :more="existMore ? more : null">
-		<p class="empty" slot="empty">%fa:R comments%%i18n:@empty%</p>
+		<p class="empty" slot="empty"><fa :icon="['far', 'comments']"/>%i18n:@empty%</p>
 	</mk-notes>
 </div>
 </template>
@@ -157,7 +157,7 @@ export default Vue.extend({
 		text-align center
 		color #999
 
-		> [data-fa]
+		> [data-icon]
 			display block
 			margin-bottom 16px
 			font-size 3em
diff --git a/src/client/app/desktop/views/pages/user/user.twitter.vue b/src/client/app/desktop/views/pages/user/user.twitter.vue
index 228ce1de9..13cea10a9 100644
--- a/src/client/app/desktop/views/pages/user/user.twitter.vue
+++ b/src/client/app/desktop/views/pages/user/user.twitter.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="adsvaidqfznoartcbplullnejvxjphcn">
-	<span>%fa:B twitter%<a :href="`https://twitter.com/${user.twitter.screenName}`" target="_blank">@{{ user.twitter.screenName }}</a></span>
+	<span><fa :icon="['fab', 'twitter']"/><a :href="`https://twitter.com/${user.twitter.screenName}`" target="_blank">@{{ user.twitter.screenName }}</a></span>
 </div>
 </template>
 
diff --git a/src/client/app/desktop/views/pages/user/user.vue b/src/client/app/desktop/views/pages/user/user.vue
index b137592c6..e36be6ac5 100644
--- a/src/client/app/desktop/views/pages/user/user.vue
+++ b/src/client/app/desktop/views/pages/user/user.vue
@@ -1,8 +1,8 @@
 <template>
 <mk-ui>
 	<div class="xygkxeaeontfaokvqmiblezmhvhostak" v-if="!fetching">
-		<div class="is-suspended" v-if="user.isSuspended">%fa:exclamation-triangle% %i18n:@is-suspended%</div>
-		<div class="is-remote" v-if="user.host">%fa:exclamation-triangle% %i18n:common.is-remote-user%<a :href="user.url || user.uri" target="_blank">%i18n:common.view-on-remote%</a></div>
+		<div class="is-suspended" v-if="user.isSuspended"><fa icon="exclamation-triangle"/> %i18n:@is-suspended%</div>
+		<div class="is-remote" v-if="user.host != null"><fa icon="exclamation-triangle"/> %i18n:common.is-remote-user%<a :href="user.url || user.uri" target="_blank">%i18n:common.view-on-remote%</a></div>
 		<main>
 			<div class="main">
 				<x-header :user="user"/>
diff --git a/src/client/app/desktop/views/pages/welcome.vue b/src/client/app/desktop/views/pages/welcome.vue
index 65651f7ff..fbb20f405 100644
--- a/src/client/app/desktop/views/pages/welcome.vue
+++ b/src/client/app/desktop/views/pages/welcome.vue
@@ -3,8 +3,8 @@
 	<div class="banner" :style="{ backgroundImage: banner ? `url(${banner})` : null }"></div>
 
 	<button @click="dark">
-		<template v-if="$store.state.device.darkmode">%fa:moon%</template>
-		<template v-else>%fa:R moon%</template>
+		<template v-if="$store.state.device.darkmode"><fa icon="moon"/></template>
+		<template v-else><fa :icon="['far', 'moon']"/></template>
 	</button>
 
 	<mk-forkit class="forkit"/>
@@ -19,8 +19,8 @@
 					<div class="info">
 						<span><b>{{ host }}</b> - <span v-html="'%i18n:@powered-by-misskey%'"></span></span>
 						<span class="stats" v-if="stats">
-							<span>%fa:user% {{ stats.originalUsersCount | number }}</span>
-							<span>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</span>
+							<span><fa icon="user"/> {{ stats.originalUsersCount | number }}</span>
+							<span><fa icon="pencil-alt"/> {{ stats.originalNotesCount | number }}</span>
 						</span>
 					</div>
 
@@ -40,7 +40,7 @@
 			</div>
 
 			<div class="announcements block">
-				<header>%fa:broadcast-tower% %i18n:@announcements%</header>
+				<header><fa icon="broadcast-tower"/> %i18n:@announcements%</header>
 				<div v-if="announcements && announcements.length > 0">
 					<div v-for="announcement in announcements">
 						<h1 v-html="announcement.title"></h1>
@@ -50,7 +50,7 @@
 			</div>
 
 			<div class="photos block">
-				<header>%fa:images% %i18n:@photos%</header>
+				<header><fa icon="images"/> %i18n:@photos%</header>
 				<div>
 					<div v-for="photo in photos" :style="`background-image: url(${photo.thumbnailUrl})`"></div>
 				</div>
@@ -76,14 +76,14 @@
 				</div>
 
 				<div class="tl block">
-					<header>%fa:comment-alt R% %i18n:@timeline%</header>
+					<header><fa :icon="['far', 'comment-alt']"/> %i18n:@timeline%</header>
 					<div>
 						<mk-welcome-timeline class="tl" :max="20"/>
 					</div>
 				</div>
 
 				<div class="info block">
-					<header>%fa:info-circle% %i18n:@info%</header>
+					<header><fa icon="info-circle"/> %i18n:@info%</header>
 					<div>
 						<div v-if="meta" class="body">
 							<p>Version: <b>{{ meta.version }}</b></p>
diff --git a/src/client/app/desktop/views/widgets/messaging.vue b/src/client/app/desktop/views/widgets/messaging.vue
index 791d2ff1b..4ab18034f 100644
--- a/src/client/app/desktop/views/widgets/messaging.vue
+++ b/src/client/app/desktop/views/widgets/messaging.vue
@@ -1,8 +1,8 @@
 <template>
 <div class="mkw-messaging">
 	<mk-widget-container :show-header="props.design == 0">
-		<template slot="header">%fa:comments%%i18n:@title%</template>
-		<button slot="func" @click="add">%fa:plus%</button>
+		<template slot="header"><fa icon="comments"/>%i18n:@title%</template>
+		<button slot="func" @click="add"><fa icon="plus"/></button>
 
 		<mk-messaging ref="index" compact @navigate="navigate"/>
 	</mk-widget-container>
diff --git a/src/client/app/desktop/views/widgets/notifications.vue b/src/client/app/desktop/views/widgets/notifications.vue
index b44261d7c..bcbec0c94 100644
--- a/src/client/app/desktop/views/widgets/notifications.vue
+++ b/src/client/app/desktop/views/widgets/notifications.vue
@@ -1,8 +1,8 @@
 <template>
 <div class="mkw-notifications">
 	<mk-widget-container :show-header="!props.compact">
-		<template slot="header">%fa:R bell%%i18n:@title%</template>
-		<!-- <button slot="func" title="%i18n:@settings%" @click="settings">%fa:cog%</button> -->
+		<template slot="header"><fa :icon="['far', 'bell']"/>%i18n:@title%</template>
+		<!-- <button slot="func" title="%i18n:@settings%" @click="settings"><fa icon="cog"/></button> -->
 
 		<mk-notifications :class="$style.notifications"/>
 	</mk-widget-container>
diff --git a/src/client/app/desktop/views/widgets/polls.vue b/src/client/app/desktop/views/widgets/polls.vue
index c10ac1ca1..368c4c4a8 100644
--- a/src/client/app/desktop/views/widgets/polls.vue
+++ b/src/client/app/desktop/views/widgets/polls.vue
@@ -1,17 +1,17 @@
 <template>
 <div class="mkw-polls">
 	<mk-widget-container :show-header="!props.compact">
-		<template slot="header">%fa:chart-pie%%i18n:@title%</template>
-		<button slot="func" title="%i18n:@refresh%" @click="fetch">%fa:sync%</button>
+		<template slot="header"><fa icon="chart-pie"/>%i18n:@title%</template>
+		<button slot="func" title="%i18n:@refresh%" @click="fetch"><fa icon="sync"/></button>
 
 		<div class="mkw-polls--body">
 			<div class="poll" v-if="!fetching && poll != null">
 				<p v-if="poll.text"><router-link :to="poll | notePage">{{ poll.text }}</router-link></p>
-				<p v-if="!poll.text"><router-link :to="poll | notePage">%fa:link%</router-link></p>
+				<p v-if="!poll.text"><router-link :to="poll | notePage"><fa icon="link"/></router-link></p>
 				<mk-poll :note="poll"/>
 			</div>
 			<p class="empty" v-if="!fetching && poll == null">%i18n:@nothing%</p>
-			<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
+			<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
 		</div>
 	</mk-widget-container>
 </div>
@@ -88,7 +88,7 @@ export default define({
 		text-align center
 		color #aaa
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 
 </style>
diff --git a/src/client/app/desktop/views/widgets/post-form.vue b/src/client/app/desktop/views/widgets/post-form.vue
index a763f4d17..01c8afec2 100644
--- a/src/client/app/desktop/views/widgets/post-form.vue
+++ b/src/client/app/desktop/views/widgets/post-form.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mkw-post-form">
 	<template v-if="props.design == 0">
-		<p class="title">%fa:pencil-alt%%i18n:@title%</p>
+		<p class="title"><fa icon="pencil-alt"/>%i18n:@title%</p>
 	</template>
 	<textarea :disabled="posting" v-model="text" @keydown="onKeydown" :placeholder="placeholder"></textarea>
 	<button @click="post" :disabled="posting">%i18n:@note%</button>
@@ -86,7 +86,7 @@ export default define({
 		color #888
 		box-shadow 0 1px rgba(#000, 0.07)
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 
 	> textarea
diff --git a/src/client/app/desktop/views/widgets/trends.vue b/src/client/app/desktop/views/widgets/trends.vue
index a88679613..b20063d54 100644
--- a/src/client/app/desktop/views/widgets/trends.vue
+++ b/src/client/app/desktop/views/widgets/trends.vue
@@ -1,11 +1,11 @@
 <template>
 <div class="mkw-trends">
 	<mk-widget-container :show-header="!props.compact">
-		<template slot="header">%fa:fire%%i18n:@title%</template>
-		<button slot="func" title="%i18n:@refresh%" @click="fetch">%fa:sync%</button>
+		<template slot="header"><fa icon="fire"/>%i18n:@title%</template>
+		<button slot="func" title="%i18n:@refresh%" @click="fetch"><fa icon="sync"/></button>
 
 		<div class="mkw-trends--body">
-			<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
+			<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
 			<div class="note" v-else-if="note != null">
 				<p class="text"><router-link :to="note | notePage">{{ note.text }}</router-link></p>
 				<p class="author">―<router-link :to="note.user | userPage">@{{ note.user | acct }}</router-link></p>
@@ -95,7 +95,7 @@ export default define({
 			text-align center
 			color #aaa
 
-			> [data-fa]
+			> [data-icon]
 				margin-right 4px
 
 </style>
diff --git a/src/client/app/desktop/views/widgets/users.vue b/src/client/app/desktop/views/widgets/users.vue
index 7501e96d9..ca55ca893 100644
--- a/src/client/app/desktop/views/widgets/users.vue
+++ b/src/client/app/desktop/views/widgets/users.vue
@@ -1,11 +1,11 @@
 <template>
 <div class="mkw-users">
 	<mk-widget-container :show-header="!props.compact">
-		<template slot="header">%fa:users%%i18n:@title%</template>
-		<button slot="func" title="%i18n:@refresh%" @click="refresh">%fa:sync%</button>
+		<template slot="header"><fa icon="users"/>%i18n:@title%</template>
+		<button slot="func" title="%i18n:@refresh%" @click="refresh"><fa icon="sync"/></button>
 
 		<div class="mkw-users--body">
-			<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
+			<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
 			<template v-else-if="users.length != 0">
 				<div class="user" v-for="_user in users">
 					<mk-avatar class="avatar" :user="_user"/>
@@ -129,7 +129,7 @@ export default define({
 			text-align center
 			color #aaa
 
-			> [data-fa]
+			> [data-icon]
 				margin-right 4px
 
 </style>
diff --git a/src/client/app/dev/views/new-app.vue b/src/client/app/dev/views/new-app.vue
index ce42b9160..6c1844b6c 100644
--- a/src/client/app/dev/views/new-app.vue
+++ b/src/client/app/dev/views/new-app.vue
@@ -13,7 +13,7 @@
 			</b-form-group>
 			<b-card header="%i18n:@authority%">
 				<b-form-group description="%i18n:@authority-desc%">
-					<b-alert show variant="warning">%fa:exclamation-triangle% %i18n:@authority-warning%</b-alert>
+					<b-alert show variant="warning"><fa icon="exclamation-triangle"/> %i18n:@authority-warning%</b-alert>
 					<b-form-checkbox-group v-model="permission" stacked>
 						<b-form-checkbox value="account-read">%i18n:@account-read%</b-form-checkbox>
 						<b-form-checkbox value="account-write">%i18n:@account-write%</b-form-checkbox>
diff --git a/src/client/app/init.ts b/src/client/app/init.ts
index d027a7059..bc5a34998 100644
--- a/src/client/app/init.ts
+++ b/src/client/app/init.ts
@@ -5,7 +5,6 @@
 import Vue from 'vue';
 import Vuex from 'vuex';
 import VueRouter from 'vue-router';
-import * as TreeView from 'vue-json-tree-view';
 import VAnimateCss from 'v-animate-css';
 import VModal from 'vue-js-modal';
 import VueSweetalert2 from 'vue-sweetalert2';
@@ -21,14 +20,110 @@ if (localStorage.getItem('theme') == null) {
 	applyTheme(lightTheme);
 }
 
+//#region FontAwesome
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
+
+/* なぜか動かない
+import faRetweet from '@fortawesome/free-solid-svg-icons/faRetweet';
+import faPlus from '@fortawesome/free-solid-svg-icons/faPlus';
+import faUser from '@fortawesome/free-solid-svg-icons/faUser';
+import faCog from '@fortawesome/free-solid-svg-icons/faCog';
+import faCheck from '@fortawesome/free-solid-svg-icons/faCheck';
+import faStar from '@fortawesome/free-solid-svg-icons/faStar';
+import faReply from '@fortawesome/free-solid-svg-icons/faReply';
+import faEllipsisH from '@fortawesome/free-solid-svg-icons/faEllipsisH';
+import faQuoteLeft from '@fortawesome/free-solid-svg-icons/faQuoteLeft';
+import faQuoteRight from '@fortawesome/free-solid-svg-icons/faQuoteRight';
+import faAngleUp from '@fortawesome/free-solid-svg-icons/faAngleUp';
+import faAngleDown from '@fortawesome/free-solid-svg-icons/faAngleDown';
+import faAt from '@fortawesome/free-solid-svg-icons/faAt';
+import faHashtag from '@fortawesome/free-solid-svg-icons/faHashtag';
+import faHome from '@fortawesome/free-solid-svg-icons/faHome';
+import faGlobe from '@fortawesome/free-solid-svg-icons/faGlobe';
+import faCircle from '@fortawesome/free-solid-svg-icons/faCircle';
+import faList from '@fortawesome/free-solid-svg-icons/faList';
+import faHeart from '@fortawesome/free-solid-svg-icons/faHeart';
+import faUnlock from '@fortawesome/free-solid-svg-icons/faUnlock';
+import faRssSquare from '@fortawesome/free-solid-svg-icons/faRssSquare';
+import faSort from '@fortawesome/free-solid-svg-icons/faSort';
+import faChartPie from '@fortawesome/free-solid-svg-icons/faChartPie';
+import faChartBar from '@fortawesome/free-solid-svg-icons/faChartBar';
+import faPencilAlt from '@fortawesome/free-solid-svg-icons/faPencilAlt';
+import faColumns from '@fortawesome/free-solid-svg-icons/faColumns';
+import faComments from '@fortawesome/free-solid-svg-icons/faComments';
+import faGamepad from '@fortawesome/free-solid-svg-icons/faGamepad';
+import faCloud from '@fortawesome/free-solid-svg-icons/faCloud';
+import faPowerOff from '@fortawesome/free-solid-svg-icons/faPowerOff';
+import faChevronCircleLeft from '@fortawesome/free-solid-svg-icons/faChevronCircleLeft';
+import faChevronCircleRight from '@fortawesome/free-solid-svg-icons/faChevronCircleRight';
+import faShareAlt from '@fortawesome/free-solid-svg-icons/faShareAlt';
+import faTimes from '@fortawesome/free-solid-svg-icons/faTimes';
+import faThumbtack from '@fortawesome/free-solid-svg-icons/faThumbtack';
+import faSearch from '@fortawesome/free-solid-svg-icons/faSearch';
+
+import farBell from '@fortawesome/free-regular-svg-icons/faBell';
+import farEnvelope from '@fortawesome/free-regular-svg-icons/faEnvelope';
+import farComments from '@fortawesome/free-regular-svg-icons/faComments';
+
+library.add(
+	faRetweet,
+	faPlus,
+	faUser,
+	faCog,
+	faCheck,
+	faStar,
+	faReply,
+	faEllipsisH,
+	faQuoteLeft,
+	faQuoteRight,
+	faAngleUp,
+	faAngleDown,
+	faAt,
+	faHashtag,
+	faHome,
+	faGlobe,
+	faCircle,
+	faList,
+	faHeart,
+	faUnlock,
+	faRssSquare,
+	faSort,
+	faChartPie,
+	faChartBar,
+	faPencilAlt,
+	faColumns,
+	faComments,
+	faGamepad,
+	faCloud,
+	faPowerOff,
+	faChevronCircleLeft,
+	faChevronCircleRight,
+	faShareAlt,
+	faTimes,
+	faThumbtack,
+	faSearch,
+	farBell,
+	farEnvelope,
+	farComments,
+);
+*/
+
+import { fas } from '@fortawesome/free-solid-svg-icons';
+import { far } from '@fortawesome/free-regular-svg-icons';
+
+library.add(fas, far);
+//#endregion
+
 Vue.use(Vuex);
 Vue.use(VueRouter);
-Vue.use(TreeView);
 Vue.use(VAnimateCss);
 Vue.use(VModal);
 Vue.use(VueHotkey);
 Vue.use(VueSweetalert2);
 
+Vue.component('fa', FontAwesomeIcon);
+
 // Register global directives
 require('./common/views/directives');
 
diff --git a/src/client/app/mobile/views/components/dialog.vue b/src/client/app/mobile/views/components/dialog.vue
index 4f935cf03..ca9ccd824 100644
--- a/src/client/app/mobile/views/components/dialog.vue
+++ b/src/client/app/mobile/views/components/dialog.vue
@@ -152,8 +152,6 @@ export default Vue.extend({
 </style>
 
 <style lang="stylus" module>
-
-
 .header
 	margin 0 0 1em 0
 	color var(--primary)
diff --git a/src/client/app/mobile/views/components/drive-file-chooser.vue b/src/client/app/mobile/views/components/drive-file-chooser.vue
index 5fca19939..c1e53c83d 100644
--- a/src/client/app/mobile/views/components/drive-file-chooser.vue
+++ b/src/client/app/mobile/views/components/drive-file-chooser.vue
@@ -3,8 +3,8 @@
 	<div class="body">
 		<header>
 			<h1>%i18n:@select-file%<span class="count" v-if="files.length > 0">({{ files.length }})</span></h1>
-			<button class="close" @click="cancel">%fa:times%</button>
-			<button v-if="multiple" class="ok" @click="ok">%fa:check%</button>
+			<button class="close" @click="cancel"><fa icon="times"/></button>
+			<button v-if="multiple" class="ok" @click="ok"><fa icon="check"/></button>
 		</header>
 		<mk-drive class="drive" ref="browser"
 			:select-file="true"
diff --git a/src/client/app/mobile/views/components/drive-folder-chooser.vue b/src/client/app/mobile/views/components/drive-folder-chooser.vue
index 6d3fba1ef..da312841d 100644
--- a/src/client/app/mobile/views/components/drive-folder-chooser.vue
+++ b/src/client/app/mobile/views/components/drive-folder-chooser.vue
@@ -3,8 +3,8 @@
 	<div class="body">
 		<header>
 			<h1>%i18n:@select-folder%</h1>
-			<button class="close" @click="cancel">%fa:times%</button>
-			<button class="ok" @click="ok">%fa:check%</button>
+			<button class="close" @click="cancel"><fa icon="times"/></button>
+			<button class="ok" @click="ok"><fa icon="check"/></button>
 		</header>
 		<mk-drive ref="browser"
 			select-folder
diff --git a/src/client/app/mobile/views/components/drive.file-detail.vue b/src/client/app/mobile/views/components/drive.file-detail.vue
index c80cb61fa..11c0d33a5 100644
--- a/src/client/app/mobile/views/components/drive.file-detail.vue
+++ b/src/client/app/mobile/views/components/drive.file-detail.vue
@@ -6,7 +6,7 @@
 			:alt="file.name"
 			:title="file.name"
 			:style="style">
-		<template v-if="kind != 'image'">%fa:file%</template>
+		<template v-if="kind != 'image'"><fa icon="file"/></template>
 		<footer v-if="kind == 'image' && file.properties && file.properties.width && file.properties.height">
 			<span class="size">
 				<span class="width">{{ file.properties.width }}</span>
@@ -28,27 +28,27 @@
 			<span class="separator"></span>
 			<span class="data-size">{{ file.datasize | bytes }}</span>
 			<span class="separator"></span>
-			<span class="created-at" @click="showCreatedAt">%fa:R clock%<mk-time :time="file.createdAt"/></span>
+			<span class="created-at" @click="showCreatedAt"><fa :icon="['far', 'clock']"/><mk-time :time="file.createdAt"/></span>
 			<template v-if="file.isSensitive">
 				<span class="separator"></span>
-				<span class="nsfw">%fa:eye-slash% %i18n:@nsfw%</span>
+				<span class="nsfw"><fa icon="eye-slash"/> %i18n:@nsfw%</span>
 			</template>
 		</div>
 	</div>
 	<div class="menu">
 		<div>
-			<ui-button link :href="`${file.url}?download`" :download="file.name">%fa:download% %i18n:@download%</ui-button>
-			<ui-button @click="rename">%fa:pencil-alt% %i18n:@rename%</ui-button>
-			<ui-button @click="move">%fa:R folder-open% %i18n:@move%</ui-button>
-			<ui-button @click="toggleSensitive" v-if="file.isSensitive">%fa:R eye% %i18n:@unmark-as-sensitive%</ui-button>
-			<ui-button @click="toggleSensitive" v-else>%fa:R eye-slash% %i18n:@mark-as-sensitive%</ui-button>
-			<ui-button @click="del">%fa:trash-alt R% %i18n:@delete%</ui-button>
+			<ui-button link :href="`${file.url}?download`" :download="file.name"><fa icon="download"/> %i18n:@download%</ui-button>
+			<ui-button @click="rename"><fa icon="pencil-alt"/> %i18n:@rename%</ui-button>
+			<ui-button @click="move"><fa :icon="['far', 'folder-open']"/> %i18n:@move%</ui-button>
+			<ui-button @click="toggleSensitive" v-if="file.isSensitive"><fa :icon="['far', 'eye']"/> %i18n:@unmark-as-sensitive%</ui-button>
+			<ui-button @click="toggleSensitive" v-else><fa :icon="['far', 'eye-slash']"/> %i18n:@mark-as-sensitive%</ui-button>
+			<ui-button @click="del"><fa :icon="['far', 'trash-alt']"/> %i18n:@delete%</ui-button>
 		</div>
 	</div>
 	<div class="hash">
 		<div>
 			<p>
-				%fa:hashtag%%i18n:@hash%
+				<fa icon="hashtag"/>%i18n:@hash%
 			</p>
 			<code>{{ file.md5 }}</code>
 		</div>
@@ -191,7 +191,7 @@ export default Vue.extend({
 
 			> .created-at
 
-				> [data-fa]
+				> [data-icon]
 					margin-right 2px
 
 			> .nsfw
@@ -220,7 +220,7 @@ export default Vue.extend({
 				color var(--text)
 				font-size 0.9em
 
-				> [data-fa]
+				> [data-icon]
 					margin-right 4px
 
 			> code
diff --git a/src/client/app/mobile/views/components/drive.file.vue b/src/client/app/mobile/views/components/drive.file.vue
index 68978bb94..3ad208f12 100644
--- a/src/client/app/mobile/views/components/drive.file.vue
+++ b/src/client/app/mobile/views/components/drive.file.vue
@@ -12,10 +12,10 @@
 				<span class="separator"></span>
 				<span class="data-size">{{ file.datasize | bytes }}</span>
 				<span class="separator"></span>
-				<span class="created-at">%fa:R clock%<mk-time :time="file.createdAt"/></span>
+				<span class="created-at"><fa :icon="['far', 'clock']"/><mk-time :time="file.createdAt"/></span>
 				<template v-if="file.isSensitive">
 					<span class="separator"></span>
-					<span class="nsfw">%fa:eye-slash% %i18n:@nsfw%</span>
+					<span class="nsfw"><fa icon="eye-slash"/> %i18n:@nsfw%</span>
 				</template>
 			</footer>
 		</div>
@@ -142,7 +142,7 @@ export default Vue.extend({
 				> .created-at
 					opacity 0.7
 
-					> [data-fa]
+					> [data-icon]
 						margin-right 2px
 
 				> .nsfw
diff --git a/src/client/app/mobile/views/components/drive.folder.vue b/src/client/app/mobile/views/components/drive.folder.vue
index 05dcbd083..e7ba05b6a 100644
--- a/src/client/app/mobile/views/components/drive.folder.vue
+++ b/src/client/app/mobile/views/components/drive.folder.vue
@@ -1,7 +1,7 @@
 <template>
 <a class="jvwxssxsytqlqvrpiymarjlzlsxskqsr" @click.prevent="onClick" :href="`/i/drive/folder/${ folder.id }`">
 	<div class="container">
-		<p class="name">%fa:folder%{{ folder.name }}</p>%fa:angle-right%
+		<p class="name"><fa icon="folder"/>{{ folder.name }}</p><fa icon="angle-right"/>
 	</div>
 </a>
 </template>
@@ -43,10 +43,10 @@ export default Vue.extend({
 			margin 0
 			padding 0
 
-			> [data-fa]
+			> [data-icon]
 				margin-right 6px
 
-		> [data-fa]
+		> [data-icon]
 			position absolute
 			top 0
 			bottom 0
diff --git a/src/client/app/mobile/views/components/drive.vue b/src/client/app/mobile/views/components/drive.vue
index 603b2ba06..dd9870a93 100644
--- a/src/client/app/mobile/views/components/drive.vue
+++ b/src/client/app/mobile/views/components/drive.vue
@@ -1,17 +1,17 @@
 <template>
 <div class="kmmwchoexgckptowjmjgfsygeltxfeqs">
 	<nav ref="nav">
-		<a @click.prevent="goRoot()" href="/i/drive">%fa:cloud%%i18n:common.drive%</a>
+		<a @click.prevent="goRoot()" href="/i/drive"><fa icon="cloud"/>%i18n:common.drive%</a>
 		<template v-for="folder in hierarchyFolders">
-			<span :key="folder.id + '>'">%fa:angle-right%</span>
+			<span :key="folder.id + '>'"><fa icon="angle-right"/></span>
 			<a :key="folder.id" @click.prevent="cd(folder)" :href="`/i/drive/folder/${folder.id}`">{{ folder.name }}</a>
 		</template>
 		<template v-if="folder != null">
-			<span>%fa:angle-right%</span>
+			<span><fa icon="angle-right"/></span>
 			<p>{{ folder.name }}</p>
 		</template>
 		<template v-if="file != null">
-			<span>%fa:angle-right%</span>
+			<span><fa icon="angle-right"/></span>
 			<p>{{ file.name }}</p>
 		</template>
 	</nav>
@@ -497,7 +497,7 @@ export default Vue.extend({
 			&:last-child
 				font-weight bold
 
-			> [data-fa]
+			> [data-icon]
 				margin-right 4px
 
 		> span
diff --git a/src/client/app/mobile/views/components/follow-button.vue b/src/client/app/mobile/views/components/follow-button.vue
index 1bf08802b..d319ed557 100644
--- a/src/client/app/mobile/views/components/follow-button.vue
+++ b/src/client/app/mobile/views/components/follow-button.vue
@@ -5,13 +5,13 @@
 	:disabled="wait"
 >
 	<template v-if="!wait">
-		<template v-if="u.hasPendingFollowRequestFromYou && u.isLocked">%fa:hourglass-half% %i18n:@request-pending%</template>
-		<template v-else-if="u.hasPendingFollowRequestFromYou && !u.isLocked">%fa:hourglass-start% %i18n:@follow-processing%</template>
-		<template v-else-if="u.isFollowing">%fa:minus% %i18n:@following%</template>
-		<template v-else-if="!u.isFollowing && u.isLocked">%fa:plus% %i18n:@follow-request%</template>
-		<template v-else-if="!u.isFollowing && !u.isLocked">%fa:plus% %i18n:@follow%</template>
+		<template v-if="u.hasPendingFollowRequestFromYou && u.isLocked"><fa icon="hourglass-half"/> %i18n:@request-pending%</template>
+		<template v-else-if="u.hasPendingFollowRequestFromYou && !u.isLocked"><fa icon="hourglass-start"/> %i18n:@follow-processing%</template>
+		<template v-else-if="u.isFollowing"><fa icon="minus"/> %i18n:@following%</template>
+		<template v-else-if="!u.isFollowing && u.isLocked"><fa icon="plus"/> %i18n:@follow-request%</template>
+		<template v-else-if="!u.isFollowing && !u.isLocked"><fa icon="plus"/> %i18n:@follow%</template>
 	</template>
-	<template v-else>%fa:spinner .pulse .fw%</template>
+	<template v-else><fa icon="spinner .pulse" fixed-width/></template>
 </button>
 </template>
 
diff --git a/src/client/app/mobile/views/components/friends-maker.vue b/src/client/app/mobile/views/components/friends-maker.vue
index dbb82f4b1..f27e7dd28 100644
--- a/src/client/app/mobile/views/components/friends-maker.vue
+++ b/src/client/app/mobile/views/components/friends-maker.vue
@@ -5,9 +5,9 @@
 		<mk-user-card v-for="user in users" :key="user.id" :user="user"/>
 	</div>
 	<p class="empty" v-if="!fetching && users.length == 0">%i18n:@empty%</p>
-	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@fetching%<mk-ellipsis/></p>
+	<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:@fetching%<mk-ellipsis/></p>
 	<a class="refresh" @click="refresh">%i18n:@refresh%</a>
-	<button class="close" @click="close" title="%i18n:@close%">%fa:times%</button>
+	<button class="close" @click="close" title="%i18n:@close%"><fa icon="times"/></button>
 </div>
 </template>
 
@@ -89,7 +89,7 @@ export default Vue.extend({
 		text-align center
 		color #aaa
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 
 	> .refresh
@@ -121,7 +121,7 @@ export default Vue.extend({
 		&:active
 			color #222
 
-		> [data-fa]
+		> [data-icon]
 			padding 10px
 
 </style>
diff --git a/src/client/app/mobile/views/components/media-image.vue b/src/client/app/mobile/views/components/media-image.vue
index 652a2ad3a..5da888984 100644
--- a/src/client/app/mobile/views/components/media-image.vue
+++ b/src/client/app/mobile/views/components/media-image.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="qjewsnkgzzxlxtzncydssfbgjibiehcy" v-if="image.isSensitive && hide && !$store.state.device.alwaysShowNsfw" @click="hide = false">
 	<div>
-		<b>%fa:exclamation-triangle% %i18n:@sensitive%</b>
+		<b><fa icon="exclamation-triangle"/> %i18n:@sensitive%</b>
 		<span>%i18n:@click-to-show%</span>
 	</div>
 </div>
diff --git a/src/client/app/mobile/views/components/media-video.vue b/src/client/app/mobile/views/components/media-video.vue
index 59ba695b9..5e1c8a250 100644
--- a/src/client/app/mobile/views/components/media-video.vue
+++ b/src/client/app/mobile/views/components/media-video.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="icozogqfvdetwohsdglrbswgrejoxbdj" v-if="video.isSensitive && hide" @click="hide = false">
 	<div>
-		<b>%fa:exclamation-triangle% %i18n:@sensitive%</b>
+		<b><fa icon="exclamation-triangle"/> %i18n:@sensitive%</b>
 		<span>%i18n:@click-to-show%</span>
 	</div>
 </div>
@@ -11,7 +11,7 @@
 	:style="imageStyle"
 	:title="video.name"
 >
-	%fa:R play-circle%
+	<fa :icon="['far', 'play-circle']"/>
 </a>
 </template>
 
diff --git a/src/client/app/mobile/views/components/note-detail.vue b/src/client/app/mobile/views/components/note-detail.vue
index 3125255c9..66fc91e78 100644
--- a/src/client/app/mobile/views/components/note-detail.vue
+++ b/src/client/app/mobile/views/components/note-detail.vue
@@ -6,8 +6,8 @@
 		@click="fetchConversation"
 		:disabled="conversationFetching"
 	>
-		<template v-if="!conversationFetching">%fa:ellipsis-v%</template>
-		<template v-if="conversationFetching">%fa:spinner .pulse%</template>
+		<template v-if="!conversationFetching"><fa icon="ellipsis-v"/></template>
+		<template v-if="conversationFetching"><fa icon="spinner .pulse"/></template>
 	</button>
 	<div class="conversation">
 		<x-sub v-for="note in conversation" :key="note.id" :note="note"/>
@@ -18,7 +18,7 @@
 	<div class="renote" v-if="isRenote">
 		<p>
 			<mk-avatar class="avatar" :user="note.user"/>
-			%fa:retweet%
+			<fa icon="retweet"/>
 			<router-link class="name" :href="note.user | userPage">{{ note.user | userName }}</router-link>
 			<span>{{ '%i18n:@reposted-by%'.substr(0, '%i18n:@reposted-by%'.indexOf('{')) }}</span>
 			<a class="name" :href="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</a>
@@ -50,7 +50,7 @@
 				</div>
 				<mk-poll v-if="p.poll" :note="p"/>
 				<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="true"/>
-				<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
+				<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank"><fa icon="map-marker-alt"/> %i18n:@location%</a>
 				<div class="map" v-if="p.geo" ref="map"></div>
 				<div class="renote" v-if="p.renote">
 					<mk-note-preview :note="p.renote"/>
@@ -63,18 +63,18 @@
 		<footer>
 			<mk-reactions-viewer :note="p"/>
 			<button @click="reply" title="%i18n:@reply%">
-				<template v-if="p.reply">%fa:reply-all%</template>
-				<template v-else>%fa:reply%</template>
+				<template v-if="p.reply"><fa icon="reply-all"/></template>
+				<template v-else><fa icon="reply"/></template>
 				<p class="count" v-if="p.repliesCount > 0">{{ p.repliesCount }}</p>
 			</button>
 			<button @click="renote" title="Renote">
-				%fa:retweet%<p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p>
+				<fa icon="retweet"/><p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p>
 			</button>
 			<button :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton" title="%i18n:@reaction%">
-				%fa:plus%<p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
+				<fa icon="plus"/><p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
 			</button>
 			<button @click="menu" ref="menuButton">
-				%fa:ellipsis-h%
+				<fa icon="ellipsis-h"/>
 			</button>
 		</footer>
 	</article>
@@ -281,7 +281,7 @@ export default Vue.extend({
 				margin 0 8px 0 0
 				border-radius 6px
 
-			[data-fa]
+			[data-icon]
 				margin-right 4px
 
 			.name
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index e1b8e05c8..44b717145 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -11,7 +11,7 @@
 	</div>
 	<div class="renote" v-if="isRenote">
 		<mk-avatar class="avatar" :user="note.user"/>
-		%fa:retweet%
+		<fa icon="retweet"/>
 		<span>{{ '%i18n:@reposted-by%'.substr(0, '%i18n:@reposted-by%'.indexOf('{')) }}</span>
 		<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>
 		<span>{{ '%i18n:@reposted-by%'.substr('%i18n:@reposted-by%'.indexOf('}') + 1) }}</span>
@@ -29,7 +29,7 @@
 				<div class="content" v-show="appearNote.cw == null || showContent">
 					<div class="text">
 						<span v-if="appearNote.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
-						<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
+						<a class="reply" v-if="appearNote.reply"><fa icon="reply"/></a>
 						<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text" :customEmojis="appearNote.emojis"/>
 						<a class="rp" v-if="appearNote.renote != null">RN:</a>
 					</div>
@@ -38,7 +38,7 @@
 					</div>
 					<mk-poll v-if="appearNote.poll" :note="appearNote" ref="pollViewer"/>
 					<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
-					<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
+					<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank"><fa icon="map-marker-alt"/> %i18n:@location%</a>
 					<div class="renote" v-if="appearNote.renote"><mk-note-preview :note="appearNote.renote"/></div>
 				</div>
 				<span class="app" v-if="appearNote.app">via <b>{{ appearNote.app.name }}</b></span>
@@ -46,18 +46,18 @@
 			<footer>
 				<mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/>
 				<button @click="reply()">
-					<template v-if="appearNote.reply">%fa:reply-all%</template>
-					<template v-else>%fa:reply%</template>
+					<template v-if="appearNote.reply"><fa icon="reply-all"/></template>
+					<template v-else><fa icon="reply"/></template>
 					<p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p>
 				</button>
 				<button @click="renote()" title="Renote">
-					%fa:retweet%<p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
+					<fa icon="retweet"/><p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
 				</button>
 				<button :class="{ reacted: appearNote.myReaction != null }" @click="react()" ref="reactButton">
-					%fa:plus%<p class="count" v-if="appearNote.reactions_count > 0">{{ appearNote.reactions_count }}</p>
+					<fa icon="plus"/><p class="count" v-if="appearNote.reactions_count > 0">{{ appearNote.reactions_count }}</p>
 				</button>
 				<button class="menu" @click="menu()" ref="menuButton">
-					%fa:ellipsis-h%
+					<fa icon="ellipsis-h"/>
 				</button>
 			</footer>
 		</div>
@@ -155,7 +155,7 @@ export default Vue.extend({
 				width 28px
 				height 28px
 
-		[data-fa]
+		[data-icon]
 			margin-right 4px
 
 		> span
diff --git a/src/client/app/mobile/views/components/notes.vue b/src/client/app/mobile/views/components/notes.vue
index 53ffe49c5..fb0927689 100644
--- a/src/client/app/mobile/views/components/notes.vue
+++ b/src/client/app/mobile/views/components/notes.vue
@@ -20,8 +20,8 @@
 		<template v-for="(note, i) in _notes">
 			<mk-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)"/>
 			<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
-				<span>%fa:angle-up%{{ note._datetext }}</span>
-				<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
+				<span><fa icon="angle-up"/>{{ note._datetext }}</span>
+				<span><fa icon="angle-down"/>{{ _notes[i + 1]._datetext }}</span>
 			</p>
 		</template>
 	</component>
@@ -29,7 +29,7 @@
 	<footer v-if="more">
 		<button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
 			<template v-if="!moreFetching">%i18n:@load-more%</template>
-			<template v-if="moreFetching">%fa:spinner .pulse .fw%</template>
+			<template v-if="moreFetching"><fa icon="spinner .pulse" fixed-width/></template>
 		</button>
 	</footer>
 </div>
@@ -233,7 +233,7 @@ export default Vue.extend({
 			span
 				margin 0 16px
 
-			[data-fa]
+			[data-icon]
 				margin-right 8px
 
 	> .placeholder
@@ -250,7 +250,7 @@ export default Vue.extend({
 		text-align center
 		color #999
 
-		> [data-fa]
+		> [data-icon]
 			display block
 			margin-bottom 16px
 			font-size 3em
diff --git a/src/client/app/mobile/views/components/notification-preview.vue b/src/client/app/mobile/views/components/notification-preview.vue
index be2c7a60e..b5f523604 100644
--- a/src/client/app/mobile/views/components/notification-preview.vue
+++ b/src/client/app/mobile/views/components/notification-preview.vue
@@ -4,22 +4,22 @@
 		<mk-avatar class="avatar" :user="notification.user"/>
 		<div class="text">
 			<p><mk-reaction-icon :reaction="notification.reaction"/>{{ notification.user | userName }}</p>
-			<p class="note-ref">%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%</p>
+			<p class="note-ref"><fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}<fa icon="quote-right"/></p>
 		</div>
 	</template>
 
 	<template v-if="notification.type == 'renote'">
 		<mk-avatar class="avatar" :user="notification.note.user"/>
 		<div class="text">
-			<p>%fa:retweet%{{ notification.note.user | userName }}</p>
-			<p class="note-ref">%fa:quote-left%{{ getNoteSummary(notification.note.renote) }}%fa:quote-right%</p>
+			<p><fa icon="retweet"/>{{ notification.note.user | userName }}</p>
+			<p class="note-ref"><fa icon="quote-left"/>{{ getNoteSummary(notification.note.renote) }}<fa icon="quote-right"/></p>
 		</div>
 	</template>
 
 	<template v-if="notification.type == 'quote'">
 		<mk-avatar class="avatar" :user="notification.note.user"/>
 		<div class="text">
-			<p>%fa:quote-left%{{ notification.note.user | userName }}</p>
+			<p><fa icon="quote-left"/>{{ notification.note.user | userName }}</p>
 			<p class="note-preview">{{ getNoteSummary(notification.note) }}</p>
 		</div>
 	</template>
@@ -27,21 +27,21 @@
 	<template v-if="notification.type == 'follow'">
 		<mk-avatar class="avatar" :user="notification.user"/>
 		<div class="text">
-			<p>%fa:user-plus%{{ notification.user | userName }}</p>
+			<p><fa icon="user-plus"/>{{ notification.user | userName }}</p>
 		</div>
 	</template>
 
 	<template v-if="notification.type == 'receiveFollowRequest'">
 		<mk-avatar class="avatar" :user="notification.user"/>
 		<div class="text">
-			<p>%fa:user-clock%{{ notification.user | userName }}</p>
+			<p><fa icon="user-clock"/>{{ notification.user | userName }}</p>
 		</div>
 	</template>
 
 	<template v-if="notification.type == 'reply'">
 		<mk-avatar class="avatar" :user="notification.note.user"/>
 		<div class="text">
-			<p>%fa:reply%{{ notification.note.user | userName }}</p>
+			<p><fa icon="reply"/>{{ notification.note.user | userName }}</p>
 			<p class="note-preview">{{ getNoteSummary(notification.note) }}</p>
 		</div>
 	</template>
@@ -49,7 +49,7 @@
 	<template v-if="notification.type == 'mention'">
 		<mk-avatar class="avatar" :user="notification.note.user"/>
 		<div class="text">
-			<p>%fa:at%{{ notification.note.user | userName }}</p>
+			<p><fa icon="at"/>{{ notification.note.user | userName }}</p>
 			<p class="note-preview">{{ getNoteSummary(notification.note) }}</p>
 		</div>
 	</template>
@@ -57,8 +57,8 @@
 	<template v-if="notification.type == 'poll_vote'">
 		<mk-avatar class="avatar" :user="notification.user"/>
 		<div class="text">
-			<p>%fa:chart-pie%{{ notification.user | userName }}</p>
-			<p class="note-ref">%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%</p>
+			<p><fa icon="chart-pie"/>{{ notification.user | userName }}</p>
+			<p class="note-ref"><fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}<fa icon="quote-right"/></p>
 		</div>
 	</template>
 </div>
@@ -110,7 +110,7 @@ export default Vue.extend({
 
 	.note-ref
 
-		[data-fa]
+		[data-icon]
 			font-size 1em
 			font-weight normal
 			font-style normal
diff --git a/src/client/app/mobile/views/components/notification.vue b/src/client/app/mobile/views/components/notification.vue
index 4a0910434..abc013f60 100644
--- a/src/client/app/mobile/views/components/notification.vue
+++ b/src/client/app/mobile/views/components/notification.vue
@@ -9,8 +9,8 @@
 				<mk-time :time="notification.createdAt"/>
 			</header>
 			<router-link class="note-ref" :to="notification.note | notePage">
-				%fa:quote-left%{{ getNoteSummary(notification.note) }}
-				%fa:quote-right%
+				<fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}
+				<fa icon="quote-right"/>
 			</router-link>
 		</div>
 	</div>
@@ -19,12 +19,12 @@
 		<mk-avatar class="avatar" :user="notification.user"/>
 		<div>
 			<header>
-				%fa:retweet%
+				<fa icon="retweet"/>
 				<router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link>
 				<mk-time :time="notification.createdAt"/>
 			</header>
 			<router-link class="note-ref" :to="notification.note | notePage">
-				%fa:quote-left%{{ getNoteSummary(notification.note.renote) }}%fa:quote-right%
+				<fa icon="quote-left"/>{{ getNoteSummary(notification.note.renote) }}<fa icon="quote-right"/>
 			</router-link>
 		</div>
 	</div>
@@ -33,7 +33,7 @@
 		<mk-avatar class="avatar" :user="notification.user"/>
 		<div>
 			<header>
-				%fa:user-plus%
+				<fa icon="user-plus"/>
 				<router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link>
 				<mk-time :time="notification.createdAt"/>
 			</header>
@@ -44,7 +44,7 @@
 		<mk-avatar class="avatar" :user="notification.user"/>
 		<div>
 			<header>
-				%fa:user-clock%
+				<fa icon="user-clock"/>
 				<router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link>
 				<mk-time :time="notification.createdAt"/>
 			</header>
@@ -55,12 +55,12 @@
 		<mk-avatar class="avatar" :user="notification.user"/>
 		<div>
 			<header>
-				%fa:chart-pie%
+				<fa icon="chart-pie"/>
 				<router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link>
 				<mk-time :time="notification.createdAt"/>
 			</header>
 			<router-link class="note-ref" :to="notification.note | notePage">
-				%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%
+				<fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}<fa icon="quote-right"/>
 			</router-link>
 		</div>
 	</div>
@@ -163,7 +163,7 @@ export default Vue.extend({
 			> .note-ref
 				color var(--noteText)
 
-				[data-fa]
+				[data-icon]
 					font-size 1em
 					font-weight normal
 					font-style normal
diff --git a/src/client/app/mobile/views/components/notifications.vue b/src/client/app/mobile/views/components/notifications.vue
index f33808a3c..3669e84ea 100644
--- a/src/client/app/mobile/views/components/notifications.vue
+++ b/src/client/app/mobile/views/components/notifications.vue
@@ -11,14 +11,14 @@
 		<template v-for="(notification, i) in _notifications">
 			<mk-notification :notification="notification" :key="notification.id"/>
 			<p class="date" :key="notification.id + '_date'" v-if="i != notifications.length - 1 && notification._date != _notifications[i + 1]._date">
-				<span>%fa:angle-up%{{ notification._datetext }}</span>
-				<span>%fa:angle-down%{{ _notifications[i + 1]._datetext }}</span>
+				<span><fa icon="angle-up"/>{{ notification._datetext }}</span>
+				<span><fa icon="angle-down"/>{{ _notifications[i + 1]._datetext }}</span>
 			</p>
 		</template>
 	</component>
 
 	<button class="more" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications">
-		<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>
+		<template v-if="fetchingMoreNotifications"><fa icon="spinner .pulse" fixed-width/></template>
 		{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
 	</button>
 
@@ -165,7 +165,7 @@ export default Vue.extend({
 			span
 				margin 0 16px
 
-			i
+			[data-icon]
 				margin-right 8px
 
 	> .more
@@ -175,7 +175,7 @@ export default Vue.extend({
 		color var(--text)
 		border-top solid 1px rgba(#000, 0.05)
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 
 	> .empty
diff --git a/src/client/app/mobile/views/components/post-form.vue b/src/client/app/mobile/views/components/post-form.vue
index 0c783fded..4a50ed982 100644
--- a/src/client/app/mobile/views/components/post-form.vue
+++ b/src/client/app/mobile/views/components/post-form.vue
@@ -2,10 +2,10 @@
 <div class="mk-post-form">
 	<div class="form">
 		<header>
-			<button class="cancel" @click="cancel">%fa:times%</button>
+			<button class="cancel" @click="cancel"><fa icon="times"/></button>
 			<div>
 				<span class="text-count" :class="{ over: trimmedLength(text) > this.maxNoteTextLength }">{{ this.maxNoteTextLength - trimmedLength(text) }}</span>
-				<span class="geo" v-if="geo">%fa:map-marker-alt%</span>
+				<span class="geo" v-if="geo"><fa icon="map-marker-alt"/></span>
 				<button class="submit" :disabled="!canPost" @click="post">{{ submitText }}</button>
 			</div>
 		</header>
@@ -28,18 +28,18 @@
 			<mk-poll-editor v-if="poll" ref="poll" @destroyed="poll = false"/>
 			<mk-uploader ref="uploader" @uploaded="attachMedia" @change="onChangeUploadings"/>
 			<footer>
-				<button class="upload" @click="chooseFile">%fa:upload%</button>
-				<button class="drive" @click="chooseFileFromDrive">%fa:cloud%</button>
-				<button class="kao" @click="kao">%fa:R smile%</button>
-				<button class="poll" @click="poll = true">%fa:chart-pie%</button>
-				<button class="poll" @click="useCw = !useCw">%fa:eye-slash%</button>
-				<button class="geo" @click="geo ? removeGeo() : setGeo()">%fa:map-marker-alt%</button>
+				<button class="upload" @click="chooseFile"><fa icon="upload"/></button>
+				<button class="drive" @click="chooseFileFromDrive"><fa icon="cloud"/></button>
+				<button class="kao" @click="kao"><fa :icon="['far', 'smile']"/></button>
+				<button class="poll" @click="poll = true"><fa icon="chart-pie"/></button>
+				<button class="poll" @click="useCw = !useCw"><fa icon="eye-slash"/></button>
+				<button class="geo" @click="geo ? removeGeo() : setGeo()"><fa icon="map-marker-alt"/></button>
 				<button class="visibility" @click="setVisibility" ref="visibilityButton">
-					<span v-if="visibility === 'public'">%fa:globe%</span>
-					<span v-if="visibility === 'home'">%fa:home%</span>
-					<span v-if="visibility === 'followers'">%fa:unlock%</span>
-					<span v-if="visibility === 'specified'">%fa:envelope%</span>
-					<span v-if="visibility === 'private'">%fa:lock%</span>
+					<span v-if="visibility === 'public'"><fa icon="globe"/></span>
+					<span v-if="visibility === 'home'"><fa icon="home"/></span>
+					<span v-if="visibility === 'followers'"><fa icon="unlock"/></span>
+					<span v-if="visibility === 'specified'"><fa icon="envelope"/></span>
+					<span v-if="visibility === 'private'"><fa icon="lock"/></span>
 				</button>
 			</footer>
 			<input ref="file" class="file" type="file" multiple="multiple" @change="onChangeFile"/>
diff --git a/src/client/app/mobile/views/components/sub-note-content.vue b/src/client/app/mobile/views/components/sub-note-content.vue
index 05d6d1d57..6a478130c 100644
--- a/src/client/app/mobile/views/components/sub-note-content.vue
+++ b/src/client/app/mobile/views/components/sub-note-content.vue
@@ -3,7 +3,7 @@
 	<div class="body">
 		<span v-if="note.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
 		<span v-if="note.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
-		<a class="reply" v-if="note.replyId">%fa:reply%</a>
+		<a class="reply" v-if="note.replyId"><fa icon="reply"/></a>
 		<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i" :customEmojis="note.emojis"/>
 		<a class="rp" v-if="note.renoteId">RN: ...</a>
 	</div>
diff --git a/src/client/app/mobile/views/components/ui.header.vue b/src/client/app/mobile/views/components/ui.header.vue
index 9793d03a8..e360e1c88 100644
--- a/src/client/app/mobile/views/components/ui.header.vue
+++ b/src/client/app/mobile/views/components/ui.header.vue
@@ -5,8 +5,8 @@
 	<div class="main" ref="main">
 		<div class="backdrop"></div>
 		<div class="content" ref="mainContainer">
-			<button class="nav" @click="$parent.isDrawerOpening = true">%fa:bars%</button>
-			<template v-if="hasUnreadNotification || hasUnreadMessagingMessage || hasGameInvitation">%fa:circle%</template>
+			<button class="nav" @click="$parent.isDrawerOpening = true"><fa icon="bars"/></button>
+			<i v-if="hasUnreadNotification || hasUnreadMessagingMessage || hasGameInvitation" class="circle"><fa icon="circle"/></i>
 			<h1>
 				<slot>{{ os.instanceName }}</slot>
 			</h1>
@@ -147,10 +147,10 @@ export default Vue.extend({
 				line-height $height
 				border-right solid 1px rgba(#000, 0.1)
 
-				> [data-fa]
+				> [data-icon]
 					transition all 0.2s ease
 
-			> [data-fa].circle
+			> i.circle
 				position absolute
 				top 8px
 				left 8px
diff --git a/src/client/app/mobile/views/components/ui.nav.vue b/src/client/app/mobile/views/components/ui.nav.vue
index 01b7d2c51..d7f0d58ae 100644
--- a/src/client/app/mobile/views/components/ui.nav.vue
+++ b/src/client/app/mobile/views/components/ui.nav.vue
@@ -15,23 +15,23 @@
 			</router-link>
 			<div class="links">
 				<ul>
-					<li><router-link to="/" :data-active="$route.name == 'index'">%fa:home%%i18n:@timeline%%fa:angle-right%</router-link></li>
-					<li><router-link to="/i/notifications" :data-active="$route.name == 'notifications'">%fa:R bell%%i18n:@notifications%<template v-if="hasUnreadNotification">%fa:circle%</template>%fa:angle-right%</router-link></li>
-					<li><router-link to="/i/messaging" :data-active="$route.name == 'messaging'">%fa:R comments%%i18n:@messaging%<template v-if="hasUnreadMessagingMessage">%fa:circle%</template>%fa:angle-right%</router-link></li>
-					<li v-if="$store.getters.isSignedIn && ($store.state.i.isLocked || $store.state.i.carefulBot)"><router-link to="/i/received-follow-requests" :data-active="$route.name == 'received-follow-requests'">%fa:R envelope%%i18n:@follow-requests%<template v-if="$store.getters.isSignedIn && $store.state.i.pendingReceivedFollowRequestsCount">%fa:circle%</template>%fa:angle-right%</router-link></li>
-					<li><router-link to="/reversi" :data-active="$route.name == 'reversi'">%fa:gamepad%%i18n:@game%<template v-if="hasGameInvitation">%fa:circle%</template>%fa:angle-right%</router-link></li>
+					<li><router-link to="/" :data-active="$route.name == 'index'"><i><fa icon="home"/></i>%i18n:@timeline%<i><fa icon="angle-right"/></i></router-link></li>
+					<li><router-link to="/i/notifications" :data-active="$route.name == 'notifications'"><i><fa :icon="['far', 'bell']"/></i>%i18n:@notifications%<i v-if="hasUnreadNotification" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
+					<li><router-link to="/i/messaging" :data-active="$route.name == 'messaging'"><i><fa :icon="['far', 'comments']"/></i>%i18n:@messaging%<i v-if="hasUnreadMessagingMessage" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
+					<li v-if="$store.getters.isSignedIn && ($store.state.i.isLocked || $store.state.i.carefulBot)"><router-link to="/i/received-follow-requests" :data-active="$route.name == 'received-follow-requests'"><i><fa :icon="['far', 'envelope']"/></i>%i18n:@follow-requests%<i v-if="$store.getters.isSignedIn && $store.state.i.pendingReceivedFollowRequestsCount" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
+					<li><router-link to="/reversi" :data-active="$route.name == 'reversi'"><i><fa icon="gamepad"/></i>%i18n:@game%<i v-if="hasGameInvitation" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
 				</ul>
 				<ul>
-					<li><router-link to="/i/widgets" :data-active="$route.name == 'widgets'">%fa:R calendar-alt%%i18n:@widgets%%fa:angle-right%</router-link></li>
-					<li><router-link to="/i/favorites" :data-active="$route.name == 'favorites'">%fa:star%%i18n:@favorites%%fa:angle-right%</router-link></li>
-					<li><router-link to="/i/lists" :data-active="$route.name == 'user-lists'">%fa:list%%i18n:@user-lists%%fa:angle-right%</router-link></li>
-					<li><router-link to="/i/drive" :data-active="$route.name == 'drive'">%fa:cloud%%i18n:common.drive%%fa:angle-right%</router-link></li>
+					<li><router-link to="/i/widgets" :data-active="$route.name == 'widgets'"><i><fa :icon="['far', 'calendar-alt']"/></i>%i18n:@widgets%<i><fa icon="angle-right"/></i></router-link></li>
+					<li><router-link to="/i/favorites" :data-active="$route.name == 'favorites'"><i><fa icon="star"/></i>%i18n:@favorites%<i><fa icon="angle-right"/></i></router-link></li>
+					<li><router-link to="/i/lists" :data-active="$route.name == 'user-lists'"><i><fa icon="list"/></i>%i18n:@user-lists%<i><fa icon="angle-right"/></i></router-link></li>
+					<li><router-link to="/i/drive" :data-active="$route.name == 'drive'"><i><fa icon="cloud"/></i>%i18n:common.drive%<i><fa icon="angle-right"/></i></router-link></li>
 				</ul>
 				<ul>
-					<li><a @click="search">%fa:search%%i18n:@search%%fa:angle-right%</a></li>
-					<li><router-link to="/i/settings" :data-active="$route.name == 'settings'">%fa:cog%%i18n:@settings%%fa:angle-right%</router-link></li>
-					<li v-if="$store.getters.isSignedIn && $store.state.i.isAdmin"><a href="/admin">%fa:terminal%<span>%i18n:@admin%</span>%fa:angle-right%</a></li>
-					<li @click="dark"><p><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template><span>%i18n:@darkmode%</span></p></li>
+					<li><a @click="search"><i><fa icon="search"/></i>%i18n:@search%<i><fa icon="angle-right"/></i></a></li>
+					<li><router-link to="/i/settings" :data-active="$route.name == 'settings'"><i><fa icon="cog"/></i>%i18n:@settings%<i><fa icon="angle-right"/></i></router-link></li>
+					<li v-if="$store.getters.isSignedIn && $store.state.i.isAdmin"><a href="/admin"><i><fa icon="terminal"/></i><span>%i18n:@admin%</span><i><fa icon="angle-right"/></i></a></li>
+					<li @click="dark"><p><template v-if="$store.state.device.darkmode"><i><fa icon="moon"/></i></template><template v-else><i><fa :icon="['far', 'moon']"/></i></template><span>%i18n:@darkmode%</span></p></li>
 				</ul>
 			</div>
 			<div class="announcements" v-if="announcements && announcements.length > 0">
@@ -195,20 +195,20 @@ export default Vue.extend({
 					color var(--primaryForeground)
 					background var(--primary)
 
-					> [data-fa]:last-child
+					> i:last-child
 						color var(--primaryForeground)
 
-				> [data-fa]:first-child
+				> i:first-child
 					margin-right 0.5em
 					width 20px
 					text-align center
 
-				> [data-fa].circle
+				> i.circle
 					margin-left 6px
 					font-size 10px
 					color var(--primary)
 
-				> [data-fa]:last-child
+				> i:last-child
 					position absolute
 					top 0
 					right 0
diff --git a/src/client/app/mobile/views/components/user-timeline.vue b/src/client/app/mobile/views/components/user-timeline.vue
index 7cd23d665..55afda0ea 100644
--- a/src/client/app/mobile/views/components/user-timeline.vue
+++ b/src/client/app/mobile/views/components/user-timeline.vue
@@ -2,7 +2,7 @@
 <div class="mk-user-timeline">
 	<mk-notes ref="timeline" :more="existMore ? more : null">
 		<div slot="empty">
-			%fa:R comments%
+			<fa :icon="['far', 'comments']"/>
 			{{ withMedia ? '%i18n:@no-notes-with-media%' : '%i18n:@no-notes%' }}
 		</div>
 	</mk-notes>
diff --git a/src/client/app/mobile/views/components/users-list.vue b/src/client/app/mobile/views/components/users-list.vue
index f06f5245b..29dd6abaa 100644
--- a/src/client/app/mobile/views/components/users-list.vue
+++ b/src/client/app/mobile/views/components/users-list.vue
@@ -14,7 +14,7 @@
 	<p class="no" v-if="!fetching && users.length == 0">
 		<slot></slot>
 	</p>
-	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
+	<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
 </div>
 </template>
 
@@ -127,7 +127,7 @@ export default Vue.extend({
 		text-align center
 		color #aaa
 
-		> [data-fa]
+		> [data-icon]
 			margin-right 4px
 
 </style>
diff --git a/src/client/app/mobile/views/components/widget-container.vue b/src/client/app/mobile/views/components/widget-container.vue
index 2a4025002..10b89dbe6 100644
--- a/src/client/app/mobile/views/components/widget-container.vue
+++ b/src/client/app/mobile/views/components/widget-container.vue
@@ -45,7 +45,7 @@ export default Vue.extend({
 			background var(--faceHeader)
 			border-radius 8px 8px 0 0
 
-			> [data-fa]
+			> [data-icon]
 				margin-right 6px
 
 			&:empty
diff --git a/src/client/app/mobile/views/pages/drive.vue b/src/client/app/mobile/views/pages/drive.vue
index 03f0686f7..4c1202f6b 100644
--- a/src/client/app/mobile/views/pages/drive.vue
+++ b/src/client/app/mobile/views/pages/drive.vue
@@ -1,11 +1,11 @@
 <template>
 <mk-ui>
 	<span slot="header">
-		<template v-if="folder"><span style="margin-right:4px;">%fa:R folder-open%</span>{{ folder.name }}</template>
+		<template v-if="folder"><span style="margin-right:4px;"><fa :icon="['far', 'folder-open']"/></span>{{ folder.name }}</template>
 		<template v-if="file"><mk-file-type-icon data-icon :type="file.type" style="margin-right:4px;"/>{{ file.name }}</template>
-		<template v-if="!folder && !file"><span style="margin-right:4px;">%fa:cloud%</span>%i18n:common.drive%</template>
+		<template v-if="!folder && !file"><span style="margin-right:4px;"><fa icon="cloud"/></span>%i18n:common.drive%</template>
 	</span>
-	<template slot="func"><button @click="fn">%fa:ellipsis-h%</button></template>
+	<template slot="func"><button @click="fn"><fa icon="ellipsis-h"/></button></template>
 	<mk-drive
 		ref="browser"
 		:init-folder="initFolder"
diff --git a/src/client/app/mobile/views/pages/favorites.vue b/src/client/app/mobile/views/pages/favorites.vue
index a25f70147..af159788b 100644
--- a/src/client/app/mobile/views/pages/favorites.vue
+++ b/src/client/app/mobile/views/pages/favorites.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-ui>
-	<span slot="header"><span style="margin-right:4px;">%fa:star%</span>%i18n:@title%</span>
+	<span slot="header"><span style="margin-right:4px;"><fa icon="star"/></span>%i18n:@title%</span>
 
 	<main>
 		<template v-for="favorite in favorites">
diff --git a/src/client/app/mobile/views/pages/games/reversi.vue b/src/client/app/mobile/views/pages/games/reversi.vue
index 7f8f91900..5b212b07d 100644
--- a/src/client/app/mobile/views/pages/games/reversi.vue
+++ b/src/client/app/mobile/views/pages/games/reversi.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-ui>
-	<span slot="header"><span style="margin-right:4px;">%fa:gamepad%</span>%i18n:@reversi%</span>
+	<span slot="header"><span style="margin-right:4px;"><fa icon="gamepad"/></span>%i18n:@reversi%</span>
 	<mk-reversi :game-id="$route.params.game" @nav="nav" :self-nav="false"/>
 </mk-ui>
 </template>
diff --git a/src/client/app/mobile/views/pages/home.timeline.vue b/src/client/app/mobile/views/pages/home.timeline.vue
index 1979747bf..4f28d23c0 100644
--- a/src/client/app/mobile/views/pages/home.timeline.vue
+++ b/src/client/app/mobile/views/pages/home.timeline.vue
@@ -4,7 +4,7 @@
 
 	<mk-notes ref="timeline" :more="existMore ? more : null">
 		<div slot="empty">
-			%fa:R comments%
+			<fa :icon="['far', 'comments']"/>
 			%i18n:@empty%
 		</div>
 	</mk-notes>
diff --git a/src/client/app/mobile/views/pages/home.vue b/src/client/app/mobile/views/pages/home.vue
index edba8585b..12c1c7f40 100644
--- a/src/client/app/mobile/views/pages/home.vue
+++ b/src/client/app/mobile/views/pages/home.vue
@@ -2,24 +2,24 @@
 <mk-ui>
 	<span slot="header" @click="showNav = true">
 		<span :class="$style.title">
-			<span v-if="src == 'home'">%fa:home%%i18n:@home%</span>
-			<span v-if="src == 'local'">%fa:R comments%%i18n:@local%</span>
-			<span v-if="src == 'hybrid'">%fa:share-alt%%i18n:@hybrid%</span>
-			<span v-if="src == 'global'">%fa:globe%%i18n:@global%</span>
-			<span v-if="src == 'mentions'">%fa:at%%i18n:@mentions%</span>
-			<span v-if="src == 'messages'">%fa:envelope R%%i18n:@messages%</span>
-			<span v-if="src == 'list'">%fa:list%{{ list.title }}</span>
-			<span v-if="src == 'tag'">%fa:hashtag%{{ tagTl.title }}</span>
+			<span v-if="src == 'home'"><fa icon="home"/>%i18n:@home%</span>
+			<span v-if="src == 'local'"><fa :icon="['far', 'comments']"/>%i18n:@local%</span>
+			<span v-if="src == 'hybrid'"><fa icon="share-alt"/>%i18n:@hybrid%</span>
+			<span v-if="src == 'global'"><fa icon="globe"/>%i18n:@global%</span>
+			<span v-if="src == 'mentions'"><fa icon="at"/>%i18n:@mentions%</span>
+			<span v-if="src == 'messages'"><fa :icon="['far', 'envelope']"/>%i18n:@messages%</span>
+			<span v-if="src == 'list'"><fa icon="list"/>{{ list.title }}</span>
+			<span v-if="src == 'tag'"><fa icon="hashtag"/>{{ tagTl.title }}</span>
 		</span>
 		<span style="margin-left:8px">
-			<template v-if="!showNav">%fa:angle-down%</template>
-			<template v-else>%fa:angle-up%</template>
+			<template v-if="!showNav"><fa icon="angle-down"/></template>
+			<template v-else><fa icon="angle-up"/></template>
 		</span>
-		<i :class="$style.badge" v-if="$store.state.i.hasUnreadMentions || $store.state.i.hasUnreadSpecifiedNotes">%fa:circle%</i>
+		<i :class="$style.badge" v-if="$store.state.i.hasUnreadMentions || $store.state.i.hasUnreadSpecifiedNotes"><fa icon="circle"/></i>
 	</span>
 
 	<template slot="func">
-		<button @click="fn">%fa:pencil-alt%</button>
+		<button @click="fn"><fa icon="pencil-alt"/></button>
 	</template>
 
 	<main>
@@ -28,19 +28,19 @@
 			<div class="pointer"></div>
 			<div class="body">
 				<div>
-					<span :data-active="src == 'home'" @click="src = 'home'">%fa:home% %i18n:@home%</span>
-					<span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline">%fa:R comments% %i18n:@local%</span>
-					<span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline">%fa:share-alt% %i18n:@hybrid%</span>
-					<span :data-active="src == 'global'" @click="src = 'global'">%fa:globe% %i18n:@global%</span>
+					<span :data-active="src == 'home'" @click="src = 'home'"><fa icon="home"/> %i18n:@home%</span>
+					<span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline"><fa :icon="['far', 'comments']"/> %i18n:@local%</span>
+					<span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline"><fa icon="share-alt"/> %i18n:@hybrid%</span>
+					<span :data-active="src == 'global'" @click="src = 'global'"><fa icon="globe"/> %i18n:@global%</span>
 					<div class="hr"></div>
-					<span :data-active="src == 'mentions'" @click="src = 'mentions'">%fa:at% %i18n:@mentions%<i class="badge" v-if="$store.state.i.hasUnreadMentions">%fa:circle%</i></span>
-					<span :data-active="src == 'messages'" @click="src = 'messages'">%fa:envelope R% %i18n:@messages%<i class="badge" v-if="$store.state.i.hasUnreadSpecifiedNotes">%fa:circle%</i></span>
+					<span :data-active="src == 'mentions'" @click="src = 'mentions'"><fa icon="at"/> %i18n:@mentions%<i class="badge" v-if="$store.state.i.hasUnreadMentions"><fa icon="circle"/></i></span>
+					<span :data-active="src == 'messages'" @click="src = 'messages'"><fa :icon="['far', 'envelope']"/> %i18n:@messages%<i class="badge" v-if="$store.state.i.hasUnreadSpecifiedNotes"><fa icon="circle"/></i></span>
 					<template v-if="lists">
 						<div class="hr" v-if="lists.length > 0"></div>
-						<span v-for="l in lists" :data-active="src == 'list' && list == l" @click="src = 'list'; list = l" :key="l.id">%fa:list% {{ l.title }}</span>
+						<span v-for="l in lists" :data-active="src == 'list' && list == l" @click="src = 'list'; list = l" :key="l.id"><fa icon="list"/> {{ l.title }}</span>
 					</template>
 					<div class="hr" v-if="$store.state.settings.tagTimelines && $store.state.settings.tagTimelines.length > 0"></div>
-					<span v-for="tl in $store.state.settings.tagTimelines" :data-active="src == 'tag' && tagTl == tl" @click="src = 'tag'; tagTl = tl" :key="tl.id">%fa:hashtag% {{ tl.title }}</span>
+					<span v-for="tl in $store.state.settings.tagTimelines" :data-active="src == 'tag' && tagTl == tl" @click="src = 'tag'; tagTl = tl" :key="tl.id"><fa icon="hashtag"/> {{ tl.title }}</span>
 				</div>
 			</div>
 		</div>
@@ -239,7 +239,7 @@ main
 
 <style lang="stylus" module>
 .title
-	i
+	[data-icon]
 		margin-right 4px
 
 .badge
diff --git a/src/client/app/mobile/views/pages/messaging-room.vue b/src/client/app/mobile/views/pages/messaging-room.vue
index 750ba2629..9974b5689 100644
--- a/src/client/app/mobile/views/pages/messaging-room.vue
+++ b/src/client/app/mobile/views/pages/messaging-room.vue
@@ -1,7 +1,7 @@
 <template>
 <mk-ui>
 	<span slot="header">
-		<template v-if="user"><span style="margin-right:4px;">%fa:R comments%</span>{{ user | userName }}</template>
+		<template v-if="user"><span style="margin-right:4px;"><fa :icon="['far', 'comments']"/></span>{{ user | userName }}</template>
 		<template v-else><mk-ellipsis/></template>
 	</span>
 	<mk-messaging-room v-if="!fetching" :user="user" :is-naked="true"/>
diff --git a/src/client/app/mobile/views/pages/messaging.vue b/src/client/app/mobile/views/pages/messaging.vue
index 98ae79fe6..4131d9ac9 100644
--- a/src/client/app/mobile/views/pages/messaging.vue
+++ b/src/client/app/mobile/views/pages/messaging.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-ui>
-	<span slot="header"><span style="margin-right:4px;">%fa:R comments%</span>%i18n:@messaging%</span>
+	<span slot="header"><span style="margin-right:4px;"><fa :icon="['far', 'comments']"/></span>%i18n:@messaging%</span>
 	<mk-messaging @navigate="navigate" :header-top="48"/>
 </mk-ui>
 </template>
diff --git a/src/client/app/mobile/views/pages/note.vue b/src/client/app/mobile/views/pages/note.vue
index d7307c79a..4e95bcf2b 100644
--- a/src/client/app/mobile/views/pages/note.vue
+++ b/src/client/app/mobile/views/pages/note.vue
@@ -1,13 +1,13 @@
 <template>
 <mk-ui>
-	<span slot="header"><span style="margin-right:4px;">%fa:R sticky-note%</span>%i18n:@title%</span>
+	<span slot="header"><span style="margin-right:4px;"><fa :icon="['far', 'sticky-note']"/></span>%i18n:@title%</span>
 	<main v-if="!fetching">
 		<div>
 			<mk-note-detail :note="note"/>
 		</div>
 		<footer>
-			<router-link v-if="note.prev" :to="note.prev">%fa:angle-left% %i18n:@prev%</router-link>
-			<router-link v-if="note.next" :to="note.next">%i18n:@next% %fa:angle-right%</router-link>
+			<router-link v-if="note.prev" :to="note.prev"><fa icon="angle-left"/> %i18n:@prev%</router-link>
+			<router-link v-if="note.next" :to="note.next">%i18n:@next% <fa icon="angle-right"/></router-link>
 		</footer>
 	</main>
 </mk-ui>
diff --git a/src/client/app/mobile/views/pages/notifications.vue b/src/client/app/mobile/views/pages/notifications.vue
index ce33332fa..54aa48a15 100644
--- a/src/client/app/mobile/views/pages/notifications.vue
+++ b/src/client/app/mobile/views/pages/notifications.vue
@@ -1,7 +1,7 @@
 <template>
 <mk-ui>
-	<span slot="header"><span style="margin-right:4px;">%fa:R bell%</span>%i18n:@notifications%</span>
-	<template slot="func"><button @click="fn">%fa:check%</button></template>
+	<span slot="header"><span style="margin-right:4px;"><fa :icon="['far', 'bell']"/></span>%i18n:@notifications%</span>
+	<template slot="func"><button @click="fn"><fa icon="check"/></button></template>
 
 	<main>
 		<mk-notifications @fetched="onFetched"/>
diff --git a/src/client/app/mobile/views/pages/received-follow-requests.vue b/src/client/app/mobile/views/pages/received-follow-requests.vue
index beaf6bba5..40e9c1cae 100644
--- a/src/client/app/mobile/views/pages/received-follow-requests.vue
+++ b/src/client/app/mobile/views/pages/received-follow-requests.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-ui>
-	<span slot="header">%fa:envelope R%%i18n:@title%</span>
+	<span slot="header"><fa :icon="['far', 'envelope']"/>%i18n:@title%</span>
 
 	<main>
 		<div v-for="req in requests">
diff --git a/src/client/app/mobile/views/pages/search.vue b/src/client/app/mobile/views/pages/search.vue
index 6e8118ff9..0f680ac57 100644
--- a/src/client/app/mobile/views/pages/search.vue
+++ b/src/client/app/mobile/views/pages/search.vue
@@ -1,9 +1,9 @@
 <template>
 <mk-ui>
-	<span slot="header">%fa:search% {{ q }}</span>
+	<span slot="header"><fa icon="search"/> {{ q }}</span>
 
 	<main>
-		<p :class="$style.empty" v-if="!fetching && empty">%fa:search% {{ '%i18n:not-found%'.split('{}')[0] }}{{ q }}{{ '%i18n:not-found%'.split('{}')[1] }}</p>
+		<p :class="$style.empty" v-if="!fetching && empty"><fa icon="search"/> {{ '%i18n:not-found%'.split('{}')[0] }}{{ q }}{{ '%i18n:not-found%'.split('{}')[1] }}</p>
 		<mk-notes ref="timeline" :more="existMore ? more : null"/>
 	</main>
 </mk-ui>
diff --git a/src/client/app/mobile/views/pages/selectdrive.vue b/src/client/app/mobile/views/pages/selectdrive.vue
index c098b8c65..408362420 100644
--- a/src/client/app/mobile/views/pages/selectdrive.vue
+++ b/src/client/app/mobile/views/pages/selectdrive.vue
@@ -2,8 +2,8 @@
 <div class="mk-selectdrive">
 	<header>
 		<h1>%i18n:@select-file%<span class="count" v-if="files.length > 0">({{ files.length }})</span></h1>
-		<button class="upload" @click="upload">%fa:upload%</button>
-		<button v-if="multiple" class="ok" @click="ok">%fa:check%</button>
+		<button class="upload" @click="upload"><fa icon="upload"/></button>
+		<button v-if="multiple" class="ok" @click="ok"><fa icon="check"/></button>
 	</header>
 	<mk-drive ref="browser" select-file :multiple="multiple" is-naked :top="$store.state.uiHeaderHeight"/>
 </div>
diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue
index 0463d9b3f..fa8018890 100644
--- a/src/client/app/mobile/views/pages/settings.vue
+++ b/src/client/app/mobile/views/pages/settings.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-ui>
-	<span slot="header"><span style="margin-right:4px;">%fa:cog%</span>%i18n:@settings%</span>
+	<span slot="header"><span style="margin-right:4px;"><fa icon="cog"/></span>%i18n:@settings%</span>
 	<main>
 		<div class="signin-as" v-html="'%i18n:@signed-in-as%'.replace('{}', `<b>${name}</b>`)"></div>
 
@@ -8,14 +8,14 @@
 			<mk-profile-editor/>
 
 			<ui-card>
-				<div slot="title">%fa:palette% %i18n:@theme%</div>
+				<div slot="title"><fa icon="palette"/> %i18n:@theme%</div>
 				<section>
 					<mk-theme/>
 				</section>
 			</ui-card>
 
 			<ui-card>
-				<div slot="title">%fa:poll-h% %i18n:@design%</div>
+				<div slot="title"><fa icon="poll-h"/> %i18n:@design%</div>
 
 				<section>
 					<ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch>
@@ -58,7 +58,7 @@
 			</ui-card>
 
 			<ui-card>
-				<div slot="title">%fa:sliders-h% %i18n:@behavior%</div>
+				<div slot="title"><fa icon="sliders-h"/> %i18n:@behavior%</div>
 
 				<section>
 					<ui-switch v-model="fetchOnScroll">%i18n:@fetch-on-scroll%</ui-switch>
@@ -89,7 +89,7 @@
 			<mk-mute-and-block/>
 
 			<ui-card>
-				<div slot="title">%fa:volume-up% %i18n:@sound%</div>
+				<div slot="title"><fa icon="volume-up"/> %i18n:@sound%</div>
 
 				<section>
 					<ui-switch v-model="enableSounds">%i18n:@enable-sounds%</ui-switch>
@@ -97,7 +97,7 @@
 			</ui-card>
 
 			<ui-card>
-				<div slot="title">%fa:language% %i18n:@lang%</div>
+				<div slot="title"><fa icon="language"/> %i18n:@lang%</div>
 
 				<section class="fit-top">
 					<ui-select v-model="lang" placeholder="%i18n:@auto%">
@@ -109,12 +109,12 @@
 							<option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</option>
 						</optgroup>
 					</ui-select>
-					<span>%fa:info-circle% %i18n:@lang-tip%</span>
+					<span><fa icon="info-circle"/> %i18n:@lang-tip%</span>
 				</section>
 			</ui-card>
 
 			<ui-card>
-				<div slot="title">%fa:B twitter% %i18n:@twitter%</div>
+				<div slot="title"><fa :icon="['fab', 'twitter']"/> %i18n:@twitter%</div>
 
 				<section>
 					<p class="account" v-if="$store.state.i.twitter"><a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p>
@@ -127,7 +127,7 @@
 			</ui-card>
 
 			<ui-card>
-				<div slot="title">%fa:B github% %i18n:@github%</div>
+				<div slot="title"><fa :icon="['fab', 'github']"/> %i18n:@github%</div>
 
 				<section>
 					<p class="account" v-if="$store.state.i.github"><a :href="`https://github.com/${$store.state.i.github.login}`" target="_blank">@{{ $store.state.i.github.login }}</a></p>
@@ -142,14 +142,14 @@
 			<mk-api-settings />
 
 			<ui-card>
-				<div slot="title">%fa:unlock-alt% %i18n:@password%</div>
+				<div slot="title"><fa icon="unlock-alt"/> %i18n:@password%</div>
 				<section>
 					<mk-password-settings/>
 				</section>
 			</ui-card>
 
 			<ui-card>
-				<div slot="title">%fa:sync-alt% %i18n:@update%</div>
+				<div slot="title"><fa icon="sync-alt"/> %i18n:@update%</div>
 
 				<section>
 					<div>%i18n:@version% <i>{{ version }}</i></div>
diff --git a/src/client/app/mobile/views/pages/share.vue b/src/client/app/mobile/views/pages/share.vue
index d75763c52..246a8afa4 100644
--- a/src/client/app/mobile/views/pages/share.vue
+++ b/src/client/app/mobile/views/pages/share.vue
@@ -4,7 +4,7 @@
 	<div>
 		<mk-signin v-if="!$store.getters.isSignedIn"/>
 		<mk-post-form v-else-if="!posted" :initial-text="text" :instant="true" @posted="posted = true"/>
-		<p v-if="posted" class="posted">%fa:check%</p>
+		<p v-if="posted" class="posted"><fa icon="check"/></p>
 	</div>
 	<ui-button class="close" v-if="posted" @click="close">%i18n:common.close%</ui-button>
 </div>
diff --git a/src/client/app/mobile/views/pages/tag.vue b/src/client/app/mobile/views/pages/tag.vue
index 3f963501e..8f70a647e 100644
--- a/src/client/app/mobile/views/pages/tag.vue
+++ b/src/client/app/mobile/views/pages/tag.vue
@@ -1,9 +1,9 @@
 <template>
 <mk-ui>
-	<span slot="header"><span style="margin-right:4px;">%fa:hashtag%</span>{{ $route.params.tag }}</span>
+	<span slot="header"><span style="margin-right:4px;"><fa icon="hashtag"/></span>{{ $route.params.tag }}</span>
 
 	<main>
-		<p v-if="!fetching && empty">%fa:search% {{ '%i18n:no-posts-found%'.split('{}')[0] }}{{ q }}{{ '%i18n:no-posts-found%'.split('{}')[1] }}</p>
+		<p v-if="!fetching && empty"><fa icon="search"/> {{ '%i18n:no-posts-found%'.split('{}')[0] }}{{ q }}{{ '%i18n:no-posts-found%'.split('{}')[1] }}</p>
 		<mk-notes ref="timeline" :more="existMore ? more : null"/>
 	</main>
 </mk-ui>
diff --git a/src/client/app/mobile/views/pages/user-list.vue b/src/client/app/mobile/views/pages/user-list.vue
index f8c8aafa6..064da3ac3 100644
--- a/src/client/app/mobile/views/pages/user-list.vue
+++ b/src/client/app/mobile/views/pages/user-list.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-ui>
-	<span slot="header" v-if="!fetching">%fa:list%{{ list.title }}</span>
+	<span slot="header" v-if="!fetching"><fa icon="list"/>{{ list.title }}</span>
 
 	<main v-if="!fetching">
 		<ul>
diff --git a/src/client/app/mobile/views/pages/user-lists.vue b/src/client/app/mobile/views/pages/user-lists.vue
index fc80f5d1c..84f07e8a9 100644
--- a/src/client/app/mobile/views/pages/user-lists.vue
+++ b/src/client/app/mobile/views/pages/user-lists.vue
@@ -1,7 +1,7 @@
 <template>
 <mk-ui>
-	<span slot="header">%fa:list%%i18n:@title%</span>
-	<template slot="func"><button @click="fn">%fa:plus%</button></template>
+	<span slot="header"><fa icon="list"/>%i18n:@title%</span>
+	<template slot="func"><button @click="fn"><fa icon="plus"/></button></template>
 
 	<main>
 		<ul>
diff --git a/src/client/app/mobile/views/pages/user.vue b/src/client/app/mobile/views/pages/user.vue
index aa8e68898..a3295d5cc 100644
--- a/src/client/app/mobile/views/pages/user.vue
+++ b/src/client/app/mobile/views/pages/user.vue
@@ -2,8 +2,8 @@
 <mk-ui>
 	<template slot="header" v-if="!fetching"><img :src="user.avatarUrl" alt="">{{ user | userName }}</template>
 	<main v-if="!fetching">
-		<div class="is-suspended" v-if="user.isSuspended"><p>%fa:exclamation-triangle% %i18n:@is-suspended%</p></div>
-		<div class="is-remote" v-if="user.host != null"><p>%fa:exclamation-triangle% %i18n:common.is-remote-user%<a :href="user.url || user.uri" target="_blank">%i18n:common.view-on-remote%</a></p></div>
+		<div class="is-suspended" v-if="user.isSuspended"><p><fa icon="exclamation-triangle"/> %i18n:@is-suspended%</p></div>
+		<div class="is-remote" v-if="user.host != null"><p><fa icon="exclamation-triangle"/> %i18n:common.is-remote-user%<a :href="user.url || user.uri" target="_blank">%i18n:common.view-on-remote%</a></p></div>
 		<header>
 			<div class="banner" :style="style"></div>
 			<div class="body">
@@ -11,7 +11,7 @@
 					<a class="avatar">
 						<img :src="user.avatarUrl" alt="avatar"/>
 					</a>
-					<button class="menu" ref="menu" @click="menu">%fa:ellipsis-h%</button>
+					<button class="menu" ref="menu" @click="menu"><fa icon="ellipsis-h"/></button>
 					<mk-follow-button v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/>
 				</div>
 				<div class="title">
@@ -24,10 +24,10 @@
 				</div>
 				<div class="info">
 					<p class="location" v-if="user.host === null && user.profile.location">
-						%fa:map-marker%{{ user.profile.location }}
+						<fa icon="map-marker"/>{{ user.profile.location }}
 					</p>
 					<p class="birthday" v-if="user.host === null && user.profile.birthday">
-						%fa:birthday-cake%{{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)
+						<fa icon="birthday-cake"/>{{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)
 					</p>
 				</div>
 				<div class="status">
@@ -48,9 +48,9 @@
 		</header>
 		<nav>
 			<div class="nav-container">
-				<a :data-active="page == 'home'" @click="page = 'home'">%fa:home% %i18n:@overview%</a>
-				<a :data-active="page == 'notes'" @click="page = 'notes'">%fa:R comment-alt% %i18n:@timeline%</a>
-				<a :data-active="page == 'media'" @click="page = 'media'">%fa:image% %i18n:@media%</a>
+				<a :data-active="page == 'home'" @click="page = 'home'"><fa icon="home"/> %i18n:@overview%</a>
+				<a :data-active="page == 'notes'" @click="page = 'notes'"><fa :icon="['far', 'comment-alt']"/> %i18n:@timeline%</a>
+				<a :data-active="page == 'media'" @click="page = 'media'"><fa icon="image"/> %i18n:@media%</a>
 			</div>
 		</nav>
 		<div class="body">
@@ -114,7 +114,7 @@ export default Vue.extend({
 
 		menu() {
 			let menu = [{
-				icon: this.user.isMuted ? '%fa:eye%' : '%fa:eye-slash%',
+				icon: this.user.isMuted ? '<fa icon="eye"/>' : '<fa icon="eye-slash"/>',
 				text: this.user.isMuted ? '%i18n:@unmute%' : '%i18n:@mute%',
 				action: () => {
 					if (this.user.isMuted) {
@@ -136,7 +136,7 @@ export default Vue.extend({
 					}
 				}
 			}, {
-				icon: this.user.isBlocking ? '%fa:user%' : '%fa:user-slash%',
+				icon: this.user.isBlocking ? '<fa icon="user"/>' : '<fa icon="user-slash"/>',
 				text: this.user.isBlocking ? '%i18n:@unblock%' : '%i18n:@block%',
 				action: () => {
 					if (this.user.isBlocking) {
diff --git a/src/client/app/mobile/views/pages/user/home.followers-you-know.vue b/src/client/app/mobile/views/pages/user/home.followers-you-know.vue
index d5e3bef96..d25d3889e 100644
--- a/src/client/app/mobile/views/pages/user/home.followers-you-know.vue
+++ b/src/client/app/mobile/views/pages/user/home.followers-you-know.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="root followers-you-know">
-	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@loading%<mk-ellipsis/></p>
+	<p class="initializing" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:@loading%<mk-ellipsis/></p>
 	<div v-if="!fetching && users.length > 0">
 		<a v-for="user in users" :key="user.id" :href="user | userPage">
 			<img :src="user.avatarUrl" :alt="user | userName"/>
diff --git a/src/client/app/mobile/views/pages/user/home.friends.vue b/src/client/app/mobile/views/pages/user/home.friends.vue
index cf257b124..29f64116b 100644
--- a/src/client/app/mobile/views/pages/user/home.friends.vue
+++ b/src/client/app/mobile/views/pages/user/home.friends.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="root friends">
-	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@loading%<mk-ellipsis/></p>
+	<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:@loading%<mk-ellipsis/></p>
 	<div v-if="!fetching && users.length > 0">
 		<mk-user-card v-for="user in users" :key="user.id" :user="user"/>
 	</div>
diff --git a/src/client/app/mobile/views/pages/user/home.notes.vue b/src/client/app/mobile/views/pages/user/home.notes.vue
index 6483402a5..bb7132cc4 100644
--- a/src/client/app/mobile/views/pages/user/home.notes.vue
+++ b/src/client/app/mobile/views/pages/user/home.notes.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="root notes">
-	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@loading%<mk-ellipsis/></p>
+	<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:@loading%<mk-ellipsis/></p>
 	<div v-if="!fetching && notes.length > 0">
 		<mk-note-card v-for="note in notes" :key="note.id" :note="note"/>
 	</div>
diff --git a/src/client/app/mobile/views/pages/user/home.photos.vue b/src/client/app/mobile/views/pages/user/home.photos.vue
index 261a3f796..e30b16cc7 100644
--- a/src/client/app/mobile/views/pages/user/home.photos.vue
+++ b/src/client/app/mobile/views/pages/user/home.photos.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="root photos">
-	<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@loading%<mk-ellipsis/></p>
+	<p class="initializing" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:@loading%<mk-ellipsis/></p>
 	<div class="stream" v-if="!fetching && images.length > 0">
 		<a v-for="image in images"
 			class="img"
diff --git a/src/client/app/mobile/views/pages/user/home.vue b/src/client/app/mobile/views/pages/user/home.vue
index 2c7134ed4..27d751260 100644
--- a/src/client/app/mobile/views/pages/user/home.vue
+++ b/src/client/app/mobile/views/pages/user/home.vue
@@ -2,31 +2,31 @@
 <div class="root home">
 	<mk-note-detail v-for="n in user.pinnedNotes" :key="n.id" :note="n" :compact="true"/>
 	<section class="recent-notes">
-		<h2>%fa:R comments%%i18n:@recent-notes%</h2>
+		<h2><fa :icon="['far', 'comments']"/>%i18n:@recent-notes%</h2>
 		<div>
 			<x-notes :user="user"/>
 		</div>
 	</section>
 	<section class="images">
-		<h2>%fa:image%%i18n:@images%</h2>
+		<h2><fa icon="image"/>%i18n:@images%</h2>
 		<div>
 			<x-photos :user="user"/>
 		</div>
 	</section>
 	<section class="activity">
-		<h2>%fa:chart-bar%%i18n:@activity%</h2>
+		<h2><fa icon="chart-bar"/>%i18n:@activity%</h2>
 		<div>
 			<mk-activity :user="user"/>
 		</div>
 	</section>
 	<section class="frequently-replied-users">
-		<h2>%fa:users%%i18n:@frequently-replied-users%</h2>
+		<h2><fa icon="users"/>%i18n:@frequently-replied-users%</h2>
 		<div>
 			<x-friends :user="user"/>
 		</div>
 	</section>
 	<section class="followers-you-know" v-if="$store.getters.isSignedIn && $store.state.i.id !== user.id">
-		<h2>%fa:users%%i18n:@followers-you-know%</h2>
+		<h2><fa icon="users"/>%i18n:@followers-you-know%</h2>
 		<div>
 			<x-followers-you-know :user="user"/>
 		</div>
diff --git a/src/client/app/mobile/views/pages/welcome.vue b/src/client/app/mobile/views/pages/welcome.vue
index 32f74bfe3..4babc47a7 100644
--- a/src/client/app/mobile/views/pages/welcome.vue
+++ b/src/client/app/mobile/views/pages/welcome.vue
@@ -23,8 +23,8 @@
 			<div v-for="photo in photos" :style="`background-image: url(${photo.thumbnailUrl})`"></div>
 		</div>
 		<div class="stats" v-if="stats">
-			<span>%fa:user% {{ stats.originalUsersCount | number }}</span>
-			<span>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</span>
+			<span><fa icon="user"/> {{ stats.originalUsersCount | number }}</span>
+			<span><fa icon="pencil-alt"/> {{ stats.originalNotesCount | number }}</span>
 		</div>
 		<div class="announcements" v-if="announcements && announcements.length > 0">
 			<article v-for="announcement in announcements">
diff --git a/src/client/app/mobile/views/pages/widgets.vue b/src/client/app/mobile/views/pages/widgets.vue
index c649529c0..cd4c75f15 100644
--- a/src/client/app/mobile/views/pages/widgets.vue
+++ b/src/client/app/mobile/views/pages/widgets.vue
@@ -1,8 +1,8 @@
 <template>
 <mk-ui>
-	<span slot="header"><span style="margin-right:4px;">%fa:home%</span>%i18n:@dashboard%</span>
+	<span slot="header"><span style="margin-right:4px;"><fa icon="home"/></span>%i18n:@dashboard%</span>
 	<template slot="func">
-		<button @click="customizing = !customizing">%fa:cog%</button>
+		<button @click="customizing = !customizing"><fa icon="cog"/></button>
 	</template>
 	<main>
 		<template v-if="customizing">
@@ -34,7 +34,7 @@
 			>
 				<div v-for="widget in widgets" class="customize-container" :key="widget.id">
 					<header>
-						<span class="handle">%fa:bars%</span>{{ widget.name }}<button class="remove" @click="removeWidget(widget)">%fa:times%</button>
+						<span class="handle"><fa icon="bars"/></span>{{ widget.name }}<button class="remove" @click="removeWidget(widget)"><fa icon="times"/></button>
 					</header>
 					<div @click="widgetFunc(widget.id)">
 						<component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-customize-mode="true" platform="mobile"/>
diff --git a/src/client/app/mobile/views/widgets/activity.vue b/src/client/app/mobile/views/widgets/activity.vue
index 350fa9258..d35613b08 100644
--- a/src/client/app/mobile/views/widgets/activity.vue
+++ b/src/client/app/mobile/views/widgets/activity.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mkw-activity">
 	<mk-widget-container :show-header="!props.compact">
-		<template slot="header">%fa:chart-bar%%i18n:@activity%</template>
+		<template slot="header"><fa icon="chart-bar"/>%i18n:@activity%</template>
 		<div :class="$style.body">
 			<mk-activity :user="$store.state.i"/>
 		</div>
diff --git a/src/docs/ui.styl b/src/docs/ui.styl
index 8d5515712..194ebd7f9 100644
--- a/src/docs/ui.styl
+++ b/src/docs/ui.styl
@@ -11,7 +11,7 @@
 	> p
 		opacity 0.8
 
-		> [data-fa]:first-child
+		> [data-icon]:first-child
 			margin-right 0.25em
 
 	&.warn
diff --git a/src/misc/fa.ts b/src/misc/fa.ts
deleted file mode 100644
index 5405255ac..000000000
--- a/src/misc/fa.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Replace fontawesome symbols
- */
-
-import * as fontawesome from '@fortawesome/fontawesome-svg-core';
-import { far } from '@fortawesome/free-regular-svg-icons';
-import { fas } from '@fortawesome/free-solid-svg-icons';
-import { fab } from '@fortawesome/free-brands-svg-icons';
-
-fontawesome.library.add(far, fas, fab);
-
-export const pattern = /%fa:(.+?)%/g;
-
-export const replacement = (match: string, key: string) => {
-	const args = key.split(' ');
-	let prefix = 'fas';
-	const classes: string[] = [];
-	let transform = '';
-	let name;
-
-	args.forEach(arg => {
-		if (arg == 'R' || arg == 'S' || arg == 'B') {
-			prefix =
-				arg == 'R' ? 'far' :
-				arg == 'S' ? 'fas' :
-				arg == 'B' ? 'fab' :
-				'';
-		} else if (arg.startsWith('.')) {
-			classes.push(`fa-${arg.substr(1)}`);
-		} else if (arg.startsWith('-')) {
-			transform = arg.substr(1).split('|').join(' ');
-		} else {
-			name = arg;
-		}
-	});
-
-	const icon = fontawesome.icon({ prefix, iconName: name } as fontawesome.IconLookup, {
-		classes: classes,
-		transform: fontawesome.parse.transform(transform)
-	});
-
-	if (icon) {
-		return `<i data-fa class="${name}">${icon.html[0]}</i>`;
-	} else {
-		console.warn(`'${name}' not found in fa`);
-		return '';
-	}
-};
-
-export default (src: string) => {
-	return src.replace(pattern, replacement);
-};
-
-export const fa = fontawesome;
diff --git a/src/server/web/index.ts b/src/server/web/index.ts
index e7332f423..42203471a 100644
--- a/src/server/web/index.ts
+++ b/src/server/web/index.ts
@@ -12,7 +12,6 @@ import * as views from 'koa-views';
 import docs from './docs';
 import User from '../../models/user';
 import parseAcct from '../../misc/acct/parse';
-import { fa } from '../../misc/fa';
 import config from '../../config';
 import Note, { pack as packNote } from '../../models/note';
 import getNoteSummary from '../../misc/get-note-summary';
@@ -28,8 +27,7 @@ app.use(views(__dirname + '/views', {
 	extension: 'pug',
 	options: {
 		config,
-		themeColor: consts.themeColor,
-		facss: fa.dom.css()
+		themeColor: consts.themeColor
 	}
 }));
 
diff --git a/webpack.config.ts b/webpack.config.ts
index 9f2416bde..03ceeaa51 100644
--- a/webpack.config.ts
+++ b/webpack.config.ts
@@ -13,7 +13,6 @@ const ProgressBarPlugin = require('progress-bar-webpack-plugin');
 
 import I18nReplacer from './src/misc/i18n';
 import { pattern as i18nPattern, replacement as i18nReplacement } from './webpack/i18n';
-import { pattern as faPattern, replacement as faReplacement } from './src/misc/fa';
 const constants = require('./src/const.json');
 
 const locales = require('./locales');
@@ -22,15 +21,11 @@ const version = meta.clientVersion;
 const codename = meta.codename;
 
 declare var global: {
-	faReplacement: typeof faReplacement;
 	collapseSpacesReplacement: any;
-	base64replacement: any;
 	i18nReplacement: typeof i18nReplacement;
 };
 
 //#region Replacer definitions
-global['faReplacement'] = faReplacement;
-
 global['collapseSpacesReplacement'] = (html: string) => {
 	return minifyHtml(html, {
 		collapseWhitespace: true,
@@ -39,10 +34,6 @@ global['collapseSpacesReplacement'] = (html: string) => {
 	}).replace(/\t/g, '');
 };
 
-global['base64replacement'] = (_: any, key: string) => {
-	return fs.readFileSync(`${__dirname}/src/client/${key}`, 'base64');
-};
-
 global['i18nReplacement'] = i18nReplacement;
 
 //#endregion
@@ -142,15 +133,9 @@ module.exports = {
 				loader: 'replace',
 				query: {
 					qs: [{
-						search: /%base64:(.+?)%/g.toString(),
-						replace: 'base64replacement'
-					}, {
 						search: i18nPattern.toString(),
 						replace: 'i18nReplacement',
 						i18n: true
-					}, {
-						search: faPattern.toString(),
-						replace: 'faReplacement'
 					}, {
 						search: /^<template>([\s\S]+?)\r?\n<\/template>/.toString(),
 						replace: 'collapseSpacesReplacement'
@@ -218,9 +203,6 @@ module.exports = {
 						search: i18nPattern.toString(),
 						replace: 'i18nReplacement',
 						i18n: true
-					}, {
-						search: faPattern.toString(),
-						replace: 'faReplacement'
 					}]
 				}
 			}]