diff --git a/src/web/app/common/views/components/index.ts b/src/web/app/common/views/components/index.ts
index 48e9e9db0..452621756 100644
--- a/src/web/app/common/views/components/index.ts
+++ b/src/web/app/common/views/components/index.ts
@@ -6,8 +6,10 @@ import forkit from './forkit.vue';
 import nav from './nav.vue';
 import postHtml from './post-html';
 import reactionIcon from './reaction-icon.vue';
+import reactionsViewer from './reactions-viewer.vue';
 import time from './time.vue';
 import images from './images.vue';
+import uploader from './uploader.vue';
 
 Vue.component('mk-signin', signin);
 Vue.component('mk-signup', signup);
@@ -15,5 +17,7 @@ Vue.component('mk-forkit', forkit);
 Vue.component('mk-nav', nav);
 Vue.component('mk-post-html', postHtml);
 Vue.component('mk-reaction-icon', reactionIcon);
+Vue.component('mk-reactions-viewer', reactionsViewer);
 Vue.component('mk-time', time);
 Vue.component('mk-images', images);
+Vue.component('mk-uploader', uploader);
diff --git a/src/web/app/common/views/components/reactions-viewer.vue b/src/web/app/common/views/components/reactions-viewer.vue
index f6e37caa4..696aef335 100644
--- a/src/web/app/common/views/components/reactions-viewer.vue
+++ b/src/web/app/common/views/components/reactions-viewer.vue
@@ -1,5 +1,5 @@
 <template>
-<div>
+<div class="mk-reactions-viewer">
 	<template v-if="reactions">
 		<span v-if="reactions.like"><mk-reaction-icon reaction='like'/><span>{{ reactions.like }}</span></span>
 		<span v-if="reactions.love"><mk-reaction-icon reaction='love'/><span>{{ reactions.love }}</span></span>
@@ -14,36 +14,36 @@
 </div>
 </template>
 
-<script lang="typescript">
-	export default {
-		props: ['post'],
-		computed: {
-			reactions() {
-				return this.post.reaction_counts;
-			}
+<script lang="ts">
+import Vue from 'vue';
+export default Vue.extend({
+	props: ['post'],
+	computed: {
+		reactions(): number {
+			return this.post.reaction_counts;
 		}
-	};
+	}
+});
 </script>
 
 <style lang="stylus" scoped>
-	:scope
-		display block
-		border-top dashed 1px #eee
-		border-bottom dashed 1px #eee
-		margin 4px 0
+.mk-reactions-viewer
+	border-top dashed 1px #eee
+	border-bottom dashed 1px #eee
+	margin 4px 0
 
-		&:empty
-			display none
+	&:empty
+		display none
+
+	> span
+		margin-right 8px
+
+		> mk-reaction-icon
+			font-size 1.4em
 
 		> span
-			margin-right 8px
-
-			> mk-reaction-icon
-				font-size 1.4em
-
-			> span
-				margin-left 4px
-				font-size 1.2em
-				color #444
+			margin-left 4px
+			font-size 1.2em
+			color #444
 
 </style>
diff --git a/src/web/app/common/views/components/uploader.vue b/src/web/app/common/views/components/uploader.vue
index 740d03ea5..21f92caab 100644
--- a/src/web/app/common/views/components/uploader.vue
+++ b/src/web/app/common/views/components/uploader.vue
@@ -19,6 +19,8 @@
 
 <script lang="ts">
 import Vue from 'vue';
+import { apiUrl } from '../../../config';
+
 export default Vue.extend({
 	data() {
 		return {
@@ -34,14 +36,15 @@ export default Vue.extend({
 			const ctx = {
 				id: id,
 				name: file.name || 'untitled',
-				progress: undefined
+				progress: undefined,
+				img: undefined
 			};
 
 			this.uploads.push(ctx);
 			this.$emit('change', this.uploads);
 
 			const reader = new FileReader();
-			reader.onload = e => {
+			reader.onload = (e: any) => {
 				ctx.img = e.target.result;
 			};
 			reader.readAsDataURL(file);
@@ -53,8 +56,8 @@ export default Vue.extend({
 			if (folder) data.append('folder_id', folder);
 
 			const xhr = new XMLHttpRequest();
-			xhr.open('POST', _API_URL_ + '/drive/files/create', true);
-			xhr.onload = e => {
+			xhr.open('POST', apiUrl + '/drive/files/create', true);
+			xhr.onload = (e: any) => {
 				const driveFile = JSON.parse(e.target.response);
 
 				this.$emit('uploaded', driveFile);
diff --git a/src/web/app/desktop/views/components/post-form-window.vue b/src/web/app/desktop/views/components/post-form-window.vue
index 77b47e20a..127233370 100644
--- a/src/web/app/desktop/views/components/post-form-window.vue
+++ b/src/web/app/desktop/views/components/post-form-window.vue
@@ -34,8 +34,8 @@ export default Vue.extend({
 		});
 	},
 	methods: {
-		onChangeUploadings(media) {
-			this.uploadings = media;
+		onChangeUploadings(files) {
+			this.uploadings = files;
 		},
 		onChangeMedia(media) {
 			this.media = media;
diff --git a/src/web/app/desktop/views/components/post-form.vue b/src/web/app/desktop/views/components/post-form.vue
index 0a5f8812d..502851316 100644
--- a/src/web/app/desktop/views/components/post-form.vue
+++ b/src/web/app/desktop/views/components/post-form.vue
@@ -22,12 +22,12 @@
 		<mk-poll-editor v-if="poll" ref="poll" @destroyed="poll = false"/>
 	</div>
 	<mk-uploader @uploaded="attachMedia" @change="onChangeUploadings"/>
-	<button ref="upload" title="%i18n:desktop.tags.mk-post-form.attach-media-from-local%" @click="selectFile">%fa:upload%</button>
-	<button ref="drive" title="%i18n:desktop.tags.mk-post-form.attach-media-from-drive%" @click="selectFileFromDrive">%fa:cloud%</button>
+	<button class="upload" title="%i18n:desktop.tags.mk-post-form.attach-media-from-local%" @click="chooseFile">%fa:upload%</button>
+	<button class="drive" title="%i18n:desktop.tags.mk-post-form.attach-media-from-drive%" @click="chooseFileFromDrive">%fa:cloud%</button>
 	<button class="kao" title="%i18n:desktop.tags.mk-post-form.insert-a-kao%" @click="kao">%fa:R smile%</button>
 	<button class="poll" title="%i18n:desktop.tags.mk-post-form.create-poll%" @click="poll = true">%fa:chart-pie%</button>
 	<p class="text-count" :class="{ over: text.length > 1000 }">{{ '%i18n:desktop.tags.mk-post-form.text-remain%'.replace('{}', 1000 - text.length) }}</p>
-	<button :class="{ posting }" ref="submit" :disabled="!canPost" @click="post">
+	<button :class="{ posting }" class="submit" :disabled="!canPost" @click="post">
 		{{ posting ? '%i18n:desktop.tags.mk-post-form.posting%' : submitText }}<mk-ellipsis v-if="posting"/>
 	</button>
 	<input ref="file" type="file" accept="image/*" multiple="multiple" tabindex="-1" @change="onChangeFile"/>
@@ -82,23 +82,25 @@ export default Vue.extend({
 		}
 	},
 	mounted() {
-		this.autocomplete = new Autocomplete(this.$refs.text);
-		this.autocomplete.attach();
+		Vue.nextTick(() => {
+			this.autocomplete = new Autocomplete(this.$refs.text);
+			this.autocomplete.attach();
 
-		// 書きかけの投稿を復元
-		const draft = JSON.parse(localStorage.getItem('drafts') || '{}')[this.draftId];
-		if (draft) {
-			this.text = draft.data.text;
-			this.files = draft.data.files;
-			if (draft.data.poll) {
-				this.poll = true;
-				(this.$refs.poll as any).set(draft.data.poll);
+			// 書きかけの投稿を復元
+			const draft = JSON.parse(localStorage.getItem('drafts') || '{}')[this.draftId];
+			if (draft) {
+				this.text = draft.data.text;
+				this.files = draft.data.files;
+				if (draft.data.poll) {
+					this.poll = true;
+					(this.$refs.poll as any).set(draft.data.poll);
+				}
+				this.$emit('change-attached-media', this.files);
 			}
-			this.$emit('change-attached-media', this.files);
-		}
 
-		new Sortable(this.$refs.media, {
-			animation: 150
+			new Sortable(this.$refs.media, {
+				animation: 150
+			});
 		});
 	},
 	beforeDestroy() {
@@ -145,7 +147,7 @@ export default Vue.extend({
 			this.text = '';
 			this.files = [];
 			this.poll = false;
-			this.$emit('change-attached-media');
+			this.$emit('change-attached-media', this.files);
 		},
 		onKeydown(e) {
 			if ((e.which == 10 || e.which == 13) && (e.ctrlKey || e.metaKey)) this.post();
@@ -187,7 +189,7 @@ export default Vue.extend({
 				// (ドライブの)ファイルだったら
 				if (obj.type == 'file') {
 					this.files.push(obj.file);
-					this.$emit('change-attached-media');
+					this.$emit('change-attached-media', this.files);
 				}
 			} catch (e) { }
 		},
@@ -260,7 +262,7 @@ export default Vue.extend({
 
 	> .content
 
-		[ref='text']
+		textarea
 			display block
 			padding 12px
 			margin 0
@@ -364,20 +366,20 @@ export default Vue.extend({
 						height 16px
 						cursor pointer
 
-		> mk-poll-editor
+		> .mk-poll-editor
 			background lighten($theme-color, 98%)
 			border solid 1px rgba($theme-color, 0.1)
 			border-top none
 			border-radius 0 0 4px 4px
 			transition border-color .3s ease
 
-	> mk-uploader
+	> .mk-uploader
 		margin 8px 0 0 0
 		padding 8px
 		border solid 1px rgba($theme-color, 0.2)
 		border-radius 4px
 
-	[ref='file']
+	input[type='file']
 		display none
 
 	.text-count
@@ -393,7 +395,7 @@ export default Vue.extend({
 		&.over
 			color #ec3828
 
-	[ref='submit']
+	.submit
 		display block
 		position absolute
 		bottom 16px
@@ -457,8 +459,8 @@ export default Vue.extend({
 				from {background-position: 0 0;}
 				to   {background-position: -64px 32px;}
 
-	[ref='upload']
-	[ref='drive']
+	.upload
+	.drive
 	.kao
 	.poll
 		display inline-block
diff --git a/src/web/app/desktop/views/components/window.vue b/src/web/app/desktop/views/components/window.vue
index 414858a1e..069d4c4f9 100644
--- a/src/web/app/desktop/views/components/window.vue
+++ b/src/web/app/desktop/views/components/window.vue
@@ -162,6 +162,7 @@ export default Vue.extend({
 			});
 
 			setTimeout(() => {
+				this.$destroy();
 				this.$emit('closed');
 			}, 300);
 		},