diff --git a/package.json b/package.json
index 689fd2cc653a272015580fbfdc97066d619996d0..0f651147bbd25370ac2b2b62a1387558fd858d4a 100644
--- a/package.json
+++ b/package.json
@@ -82,6 +82,7 @@
 		"autwh": "0.0.1",
 		"bcryptjs": "2.4.3",
 		"body-parser": "1.18.2",
+		"bootstrap-vue": "^2.0.0-rc.1",
 		"cache-loader": "1.2.0",
 		"cafy": "3.2.1",
 		"chai": "4.1.2",
diff --git a/src/web/app/dev/script.ts b/src/web/app/dev/script.ts
index 757bfca490cd0b511748b4233f78899222247743..2f4a16fab1e0be9cf17fcf949b0a679b50b7b9c5 100644
--- a/src/web/app/dev/script.ts
+++ b/src/web/app/dev/script.ts
@@ -2,6 +2,11 @@
  * Developer Center
  */
 
+import Vue from 'vue';
+import BootstrapVue from 'bootstrap-vue';
+import 'bootstrap/dist/css/bootstrap.css';
+import 'bootstrap-vue/dist/bootstrap-vue.css';
+
 // Style
 import './style.styl';
 
@@ -11,6 +16,11 @@ import Index from './views/index.vue';
 import Apps from './views/apps.vue';
 import AppNew from './views/new-app.vue';
 import App from './views/app.vue';
+import ui from './views/ui.vue';
+
+Vue.use(BootstrapVue);
+
+Vue.component('mk-ui', ui);
 
 /**
  * init
@@ -22,7 +32,7 @@ init(launch => {
 	// Routing
 	app.$router.addRoutes([
 		{ path: '/', component: Index },
-		{ path: '/app', component: Apps },
+		{ path: '/apps', component: Apps },
 		{ path: '/app/new', component: AppNew },
 		{ path: '/app/:id', component: App },
 	]);
diff --git a/src/web/app/dev/style.styl b/src/web/app/dev/style.styl
index cdbcb0e2615b0f773f21dc6f7cc467d5f6afdbc2..e635897b170fee1f653983f1676d1d960350d35f 100644
--- a/src/web/app/dev/style.styl
+++ b/src/web/app/dev/style.styl
@@ -1,5 +1,10 @@
 @import "../app"
 @import "../reset"
 
+// Bootstrapのデザインを崩すので:
+*
+	position initial
+	background-clip initial !important
+
 html
 	background-color #fff
diff --git a/src/web/app/dev/views/app.vue b/src/web/app/dev/views/app.vue
index 9eddabbec22560f8b6df069db7dd6099c924da29..2c2a3c83ce7834eae7b63dd2313d35f5146befdb 100644
--- a/src/web/app/dev/views/app.vue
+++ b/src/web/app/dev/views/app.vue
@@ -1,16 +1,12 @@
 <template>
-<div>
+<mk-ui>
 	<p v-if="fetching">読み込み中</p>
-	<main v-if="!fetching">
-		<header>
-			<h1>{{ app.name }}</h1>
-		</header>
-		<div class="body">
-			<p>App Secret</p>
-			<input :value="app.secret" readonly/>
-		</div>
-	</main>
-</div>
+	<b-card v-if="!fetching" :header="app.name">
+		<b-form-group label="App Secret">
+			<b-input :value="app.secret" readonly/>
+		</b-form-group>
+	</b-card>
+</mk-ui>
 </template>
 
 <script lang="ts">
diff --git a/src/web/app/dev/views/apps.vue b/src/web/app/dev/views/apps.vue
index 42b4abc9b848a40c263bfba346cf90d129ab3570..7e0b107a3079c6ead31086bb2a0c32b22ace5925 100644
--- a/src/web/app/dev/views/apps.vue
+++ b/src/web/app/dev/views/apps.vue
@@ -1,21 +1,21 @@
 <template>
-<div>
-	<h1>アプリを管理</h1>
-	<router-link to="/app/new">アプリ作成</router-link>
-	<div class="apps">
-		<p v-if="fetching">読み込み中</p>
-		<template v-if="!fetching">
-			<p v-if="apps.length == 0">アプリなし</p>
-			<ul v-else>
-				<li v-for="app in apps" :key="app.id">
-					<router-link :to="`/app/${app.id}`">
-						<p class="name">{{ app.name }}</p>
-					</router-link>
-				</li>
-			</ul>
-		</template>
-	</div>
-</div>
+<mk-ui>
+	<b-card header="アプリを管理">
+		<b-button to="/app/new" variant="primary">アプリ作成</b-button>
+		<hr>
+		<div class="apps">
+			<p v-if="fetching">読み込み中</p>
+			<template v-if="!fetching">
+				<b-alert v-if="apps.length == 0">アプリなし</b-alert>
+				<b-list-group v-else>
+					<b-list-group-item v-for="app in apps" :key="app.id" :to="`/app/${app.id}`">
+						{{ app.name }}
+					</b-list-group-item>
+				</b-list-group>
+			</template>
+		</div>
+	</b-card>
+</mk-ui>
 </template>
 
 <script lang="ts">
diff --git a/src/web/app/dev/views/index.vue b/src/web/app/dev/views/index.vue
index a8429a56ddc10df3413ded4d86768cde5c3720ec..3f572b390707f4842e97d05936309728854b56da 100644
--- a/src/web/app/dev/views/index.vue
+++ b/src/web/app/dev/views/index.vue
@@ -1,7 +1,7 @@
 <template>
-<div>
-	<router-link to="/app">アプリ</router-link>
-</div>
+<mk-ui>
+	<b-button to="/apps" variant="primary">アプリの管理</b-button>
+</mk-ui>
 </template>
 
 <script lang="ts">
diff --git a/src/web/app/dev/views/new-app.vue b/src/web/app/dev/views/new-app.vue
index f2e5659a4e03f668de280a23cfd33ba20ccfd91c..344e8468f929b78288309d8c87c41c0c63380cbf 100644
--- a/src/web/app/dev/views/new-app.vue
+++ b/src/web/app/dev/views/new-app.vue
@@ -1,16 +1,12 @@
 <template>
-<div>
-	<form @submit="onSubmit" autocomplete="off">
-		<section class="name">
-			<label>
-				<p class="caption">アプリケーション名</p>
-				<input v-model="name" type="text" placeholder="ex) Misskey for iOS" autocomplete="off" required/>
-			</label>
-		</section>
-		<section class="nid">
-			<label>
-				<p class="caption">Named ID</p>
-				<input v-model="nid" type="text" pattern="^[a-zA-Z0-9-]{3,30}$" placeholder="ex) misskey-for-ios" autocomplete="off" required/>
+<mk-ui>
+	<b-card header="アプリケーションの作成">
+		<b-form @submit.prevent="onSubmit" autocomplete="off">
+			<b-form-group label="アプリケーション名" description="あなたのアプリの名称。">
+				<b-form-input v-model="name" type="text" placeholder="ex) Misskey for iOS" autocomplete="off" required/>
+			</b-form-group>
+			<b-form-group label="ID" description="あなたのアプリのID。">
+				<b-input v-model="nid" type="text" pattern="^[a-zA-Z0-9-]{3,30}$" placeholder="ex) misskey-for-ios" autocomplete="off" required/>
 				<p class="info" v-if="nidState == 'wait'" style="color:#999">%fa:spinner .pulse .fw%確認しています...</p>
 				<p class="info" v-if="nidState == 'ok'" style="color:#3CB7B5">%fa:fw check%利用できます</p>
 				<p class="info" v-if="nidState == 'unavailable'" style="color:#FF1161">%fa:fw exclamation-triangle%既に利用されています</p>
@@ -18,65 +14,34 @@
 				<p class="info" v-if="nidState == 'invalid-format'" style="color:#FF1161">%fa:fw exclamation-triangle%a~z、A~Z、0~9、-(ハイフン)が使えます</p>
 				<p class="info" v-if="nidState == 'min-range'" style="color:#FF1161">%fa:fw exclamation-triangle%3文字以上でお願いします!</p>
 				<p class="info" v-if="nidState == 'max-range'" style="color:#FF1161">%fa:fw exclamation-triangle%30文字以内でお願いします</p>
-			</label>
-		</section>
-		<section class="description">
-			<label>
-				<p class="caption">アプリの概要</p>
-				<textarea v-model="description" placeholder="ex) Misskey iOSクライアント。" autocomplete="off" required></textarea>
-			</label>
-		</section>
-		<section class="callback">
-			<label>
-				<p class="caption">コールバックURL (オプション)</p>
-				<input v-model="cb" type="url" placeholder="ex) https://your.app.example.com/callback.php" autocomplete="off"/>
-			</label>
-		</section>
-		<section class="permission">
-			<p class="caption">権限</p>
-			<div ref="permission">
-				<label>
-					<input type="checkbox" value="account-read"/>
-					<p>アカウントの情報を見る。</p>
-				</label>
-				<label>
-					<input type="checkbox" value="account-write"/>
-					<p>アカウントの情報を操作する。</p>
-				</label>
-				<label>
-					<input type="checkbox" value="post-write"/>
-					<p>投稿する。</p>
-				</label>
-				<label>
-					<input type="checkbox" value="reaction-write"/>
-					<p>リアクションしたりリアクションをキャンセルする。</p>
-				</label>
-				<label>
-					<input type="checkbox" value="following-write"/>
-					<p>フォローしたりフォロー解除する。</p>
-				</label>
-				<label>
-					<input type="checkbox" value="drive-read"/>
-					<p>ドライブを見る。</p>
-				</label>
-				<label>
-					<input type="checkbox" value="drive-write"/>
-					<p>ドライブを操作する。</p>
-				</label>
-				<label>
-					<input type="checkbox" value="notification-read"/>
-					<p>通知を見る。</p>
-				</label>
-				<label>
-					<input type="checkbox" value="notification-write"/>
-					<p>通知を操作する。</p>
-				</label>
-			</div>
-			<p>%fa:exclamation-triangle%アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。</p>
-		</section>
-		<button type="submit">アプリ作成</button>
-	</form>
-</div>
+			</b-form-group>
+			<b-form-group label="アプリの概要" description="あなたのアプリの簡単な説明や紹介。">
+				<b-textarea v-model="description" placeholder="ex) Misskey iOSクライアント。" autocomplete="off" required></b-textarea>
+			</b-form-group>
+			<b-form-group label="コールバックURL (オプション)" description="ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。">
+				<b-input v-model="cb" type="url" placeholder="ex) https://your.app.example.com/callback.php" autocomplete="off"/>
+			</b-form-group>
+			<b-card header="権限">
+				<b-form-group description="ここで要求した機能だけがAPIからアクセスできます。">
+					<b-alert show variant="warning">%fa:exclamation-triangle%アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。</b-alert>
+					<b-form-checkbox-group v-model="permission" stacked>
+						<b-form-checkbox value="account-read">アカウントの情報を見る。</b-form-checkbox>
+						<b-form-checkbox value="account-write">アカウントの情報を操作する。</b-form-checkbox>
+						<b-form-checkbox value="post-write">投稿する。</b-form-checkbox>
+						<b-form-checkbox value="reaction-write">リアクションしたりリアクションをキャンセルする。</b-form-checkbox>
+						<b-form-checkbox value="following-write">フォローしたりフォロー解除する。</b-form-checkbox>
+						<b-form-checkbox value="drive-read">ドライブを見る。</b-form-checkbox>
+						<b-form-checkbox value="drive-write">ドライブを操作する。</b-form-checkbox>
+						<b-form-checkbox value="notification-read">通知を見る。</b-form-checkbox>
+						<b-form-checkbox value="notification-write">通知を操作する。</b-form-checkbox>
+					</b-form-checkbox-group>
+				</b-form-group>
+			</b-card>
+			<hr>
+			<b-button type="submit" variant="primary">アプリ作成</b-button>
+		</b-form>
+	</b-card>
+</mk-ui>
 </template>
 
 <script lang="ts">
@@ -88,7 +53,8 @@ export default Vue.extend({
 			nid: '',
 			description: '',
 			cb: '',
-			nidState: null
+			nidState: null,
+			permission: []
 		};
 	},
 	watch: {
@@ -122,18 +88,12 @@ export default Vue.extend({
 	},
 	methods: {
 		onSubmit() {
-			const permission = [];
-
-			(this.$refs.permission as any).querySelectorAll('input').forEach(el => {
-				if (el.checked) permission.push(el.value);
-			});
-
 			(this as any).api('app/create', {
 				name: this.name,
 				name_id: this.nid,
 				description: this.description,
 				callback_url: this.cb,
-				permission: permission
+				permission: this.permission
 			}).then(() => {
 				location.href = '/apps';
 			}).catch(() => {
diff --git a/src/web/app/dev/views/ui.vue b/src/web/app/dev/views/ui.vue
new file mode 100644
index 0000000000000000000000000000000000000000..4a0fcee635beb9e82b619c196fa0979720ae0414
--- /dev/null
+++ b/src/web/app/dev/views/ui.vue
@@ -0,0 +1,20 @@
+<template>
+<div>
+	<b-navbar toggleable="md" type="dark" variant="info">
+		<b-navbar-brand>Misskey Developers</b-navbar-brand>
+		<b-navbar-nav>
+			<b-nav-item to="/">Home</b-nav-item>
+			<b-nav-item to="/apps">Apps</b-nav-item>
+		</b-navbar-nav>
+	</b-navbar>
+	<main>
+		<slot></slot>
+	</main>
+</div>
+</template>
+
+<style lang="stylus" scoped>
+main
+	padding 32px
+	max-width 700px
+</style>