diff --git a/src/store/modules/emojiPacks.js b/src/store/modules/emojiPacks.js
index 282a069e3f1d6b4b88a6a6094dbfa0587eb80d5c..f92e0fa533338989b801f4a5ca7cb7cf65fd0492 100644
--- a/src/store/modules/emojiPacks.js
+++ b/src/store/modules/emojiPacks.js
@@ -15,11 +15,15 @@ import Vue from 'vue'
 
 const packs = {
   state: {
+    activeCollapseItems: [],
     localPacks: {},
     remoteInstance: '',
     remotePacks: {}
   },
   mutations: {
+    SET_ACTIVE_COLLAPSE_ITEMS: (state, items) => {
+      state.activeCollapseItems = items
+    },
     SET_LOCAL_PACKS: (state, packs) => {
       state.localPacks = packs
     },
@@ -99,6 +103,9 @@ const packs = {
         commit('UPDATE_LOCAL_PACK_PACK', { name: packName, pack: result.data })
       }
     },
+    SetActiveCollapseItems({ commit, state }, activeItems) {
+      commit('SET_ACTIVE_COLLAPSE_ITEMS', activeItems)
+    },
     async SetLocalEmojiPacks({ commit, getters }) {
       const { data } = await listPacks(getters.authHost)
       commit('SET_LOCAL_PACKS', data)
diff --git a/src/views/emojiPacks/components/EmojiPack.vue b/src/views/emojiPacks/components/LocalEmojiPack.vue
similarity index 71%
rename from src/views/emojiPacks/components/EmojiPack.vue
rename to src/views/emojiPacks/components/LocalEmojiPack.vue
index d31fcf8a833cc0e213e649f54a6f14c8140c19ec..917ff4dd52d4a6609dc3ffad013473ada9803dcb 100644
--- a/src/views/emojiPacks/components/EmojiPack.vue
+++ b/src/views/emojiPacks/components/LocalEmojiPack.vue
@@ -1,6 +1,6 @@
 <template>
   <el-collapse-item :title="name" :name="name" class="has-background">
-    <el-form v-if="isLocal" :label-width="labelWidth" label-position="left" size="small" class="emoji-pack-metadata">
+    <el-form :label-width="labelWidth" label-position="left" size="small" class="emoji-pack-metadata">
       <el-form-item :label=" $t('emoji.sharePack')">
         <el-switch v-model="share" />
       </el-form-item>
@@ -22,7 +22,7 @@
         {{ pack.pack["fallback-src-sha256"] }}
       </el-form-item>
     </el-form>
-    <div v-if="isLocal" class="pack-button-container">
+    <div class="pack-button-container">
       <div class="save-pack-button-container">
         <el-button type="primary" class="save-pack-button" @click="savePackMetadata">{{ $t('emoji.saveMetadata') }}</el-button>
         <el-button class="delete-pack-button" @click="deletePack">{{ $t('emoji.deletePack') }}</el-button>
@@ -38,38 +38,6 @@
         </el-link>
       </div>
     </div>
-    <el-form v-if="!isLocal" :label-width="labelWidth" label-position="left" size="small" class="emoji-pack-metadata remote-pack-metadata">
-      <el-form-item :label=" $t('emoji.sharePack')">
-        <el-switch v-model="share" disabled />
-      </el-form-item>
-      <el-form-item v-if="homepage" :label=" $t('emoji.homepage')">
-        <span>{{ homepage }}</span>
-      </el-form-item>
-      <el-form-item v-if="description" :label=" $t('emoji.description')">
-        <span>{{ description }}</span>
-      </el-form-item>
-      <el-form-item v-if="license" :label=" $t('emoji.license')">
-        <span>{{ license }}</span>
-      </el-form-item>
-      <el-form-item v-if="fallbackSrc" :label=" $t('emoji.fallbackSrc')">
-        <span>{{ fallbackSrc }}</span>
-      </el-form-item>
-      <el-form-item
-        v-if="fallbackSrc && fallbackSrc.trim() !== ''"
-        :label=" $t('emoji.fallbackSrcSha')">
-        {{ pack.pack["fallback-src-sha256"] }}
-      </el-form-item>
-      <el-form-item>
-        <el-link
-          v-if="pack.pack['can-download']"
-          :href="pack.pack['fallback-src']"
-          :underline="false"
-          type="primary"
-          target="_blank">
-          <el-button class="download-archive">{{ $t('emoji.downloadPackArchive') }}</el-button>
-        </el-link>
-      </el-form-item>
-    </el-form>
     <el-collapse v-model="showPackContent" class="contents-collapse">
       <el-collapse-item v-if="isLocal" :title=" $t('emoji.addNewEmoji')" name="addEmoji" class="no-background">
         <new-emoji-uploader :pack-name="name"/>
@@ -84,19 +52,6 @@
           :file="file"
           :is-local="isLocal" />
       </el-collapse-item>
-      <el-collapse-item v-if="!isLocal" :title=" $t('emoji.downloadPack')" name="downloadPack" class="no-background">
-        <p>
-          {{ $t('emoji.thisWillDownload') }} "{{ name }}" {{ $t('emoji.downloadToCurrentInstance') }}
-          "{{ downloadSharedAs.trim() === '' ? name : downloadSharedAs }}" ({{ $t('emoji.canBeChanged') }}).
-          {{ $t('emoji.willBeUsable') }}.
-        </p>
-        <div class="download-shared-pack">
-          <el-input v-model="downloadSharedAs" :placeholder=" $t('emoji.downloadAsOptional')"/>
-          <el-button type="primary" class="download-shared-pack-button" @click="downloadFromInstance(pack.pack['homepage'])">
-            {{ isDesktop ? $t('emoji.downloadSharedPack') : $t('emoji.downloadSharedPackMobile') }}
-          </el-button>
-        </div>
-      </el-collapse-item>
     </el-collapse>
   </el-collapse-item>
 </template>
@@ -125,17 +80,12 @@ export default {
       required: true
     }
   },
-
   data() {
     return {
-      showPackContent: [],
-      downloadSharedAs: ''
+      showPackContent: []
     }
   },
   computed: {
-    isDesktop() {
-      return this.$store.state.app.device === 'desktop'
-    },
     isMobile() {
       return this.$store.state.app.device === 'mobile'
     },
@@ -209,15 +159,6 @@ export default {
     }
   },
   methods: {
-    downloadFromInstance(url) {
-      const instanceAddress = `${new URL(url).protocol}//${new URL(url).hostname}`
-      this.$store.dispatch(
-        'DownloadFrom',
-        { instanceAddress, packName: this.name, as: this.downloadSharedAs }
-      ).then(() => this.$store.dispatch('ReloadEmoji'))
-        .then(() => this.$store.dispatch('SetLocalEmojiPacks'))
-    },
-
     deletePack() {
       this.$confirm('This will delete the pack, are you sure?', 'Warning', {
         confirmButtonText: 'Yes, delete the pack',
@@ -229,7 +170,6 @@ export default {
           .then(() => this.$store.dispatch('SetLocalEmojiPacks'))
       }).catch(() => {})
     },
-
     savePackMetadata() {
       this.$store.dispatch('SavePackMetadata', { packName: this.name })
     }
diff --git a/src/views/emojiPacks/components/RemoteEmojiPack.vue b/src/views/emojiPacks/components/RemoteEmojiPack.vue
new file mode 100644
index 0000000000000000000000000000000000000000..0c9ecaf3f59639ac16c9a59b5efb683d54363286
--- /dev/null
+++ b/src/views/emojiPacks/components/RemoteEmojiPack.vue
@@ -0,0 +1,282 @@
+<template>
+  <el-collapse-item :title="name" :name="name" class="has-background">
+    <div v-if="loadRemotePack">
+      <el-form :label-width="labelWidth" label-position="left" size="small" class="emoji-pack-metadata remote-pack-metadata">
+        <el-form-item :label=" $t('emoji.sharePack')">
+          <el-switch v-model="share" disabled />
+        </el-form-item>
+        <el-form-item v-if="homepage" :label=" $t('emoji.homepage')">
+          <span>{{ homepage }}</span>
+        </el-form-item>
+        <el-form-item v-if="description" :label=" $t('emoji.description')">
+          <span>{{ description }}</span>
+        </el-form-item>
+        <el-form-item v-if="license" :label=" $t('emoji.license')">
+          <span>{{ license }}</span>
+        </el-form-item>
+        <el-form-item v-if="fallbackSrc" :label=" $t('emoji.fallbackSrc')">
+          <span>{{ fallbackSrc }}</span>
+        </el-form-item>
+        <el-form-item
+          v-if="fallbackSrc && fallbackSrc.trim() !== ''"
+          :label=" $t('emoji.fallbackSrcSha')">
+          {{ pack.pack["fallback-src-sha256"] }}
+        </el-form-item>
+        <el-form-item>
+          <el-link
+            v-if="pack.pack['can-download']"
+            :href="pack.pack['fallback-src']"
+            :underline="false"
+            type="primary"
+            target="_blank">
+            <el-button class="download-archive">{{ $t('emoji.downloadPackArchive') }}</el-button>
+          </el-link>
+        </el-form-item>
+      </el-form>
+      <el-collapse v-model="showPackContent" class="contents-collapse">
+        <el-collapse-item v-if="Object.keys(pack.files).length > 0" :title=" $t('emoji.manageEmoji')" name="manageEmoji" class="no-background">
+          <single-emoji-editor
+            v-for="(file, ename) in pack.files"
+            :key="ename"
+            :host="host"
+            :pack-name="name"
+            :name="ename"
+            :file="file"
+            :is-local="isLocal" />
+        </el-collapse-item>
+        <el-collapse-item :title=" $t('emoji.downloadPack')" name="downloadPack" class="no-background">
+          <p>
+            {{ $t('emoji.thisWillDownload') }} "{{ name }}" {{ $t('emoji.downloadToCurrentInstance') }}
+            "{{ downloadSharedAs.trim() === '' ? name : downloadSharedAs }}" ({{ $t('emoji.canBeChanged') }}).
+            {{ $t('emoji.willBeUsable') }}.
+          </p>
+          <div class="download-shared-pack">
+            <el-input v-model="downloadSharedAs" :placeholder=" $t('emoji.downloadAsOptional')"/>
+            <el-button type="primary" class="download-shared-pack-button" @click="downloadFromInstance(pack.pack['homepage'])">
+              {{ isDesktop ? $t('emoji.downloadSharedPack') : $t('emoji.downloadSharedPackMobile') }}
+            </el-button>
+          </div>
+        </el-collapse-item>
+      </el-collapse>
+    </div>
+  </el-collapse-item>
+</template>
+
+<script>
+import SingleEmojiEditor from './SingleEmojiEditor.vue'
+
+export default {
+  components: { SingleEmojiEditor },
+  props: {
+    name: {
+      type: String,
+      required: true
+    },
+    pack: {
+      type: Object,
+      required: true
+    },
+    host: {
+      type: String,
+      required: true
+    },
+    isLocal: {
+      type: Boolean,
+      required: true
+    }
+  },
+  data() {
+    return {
+      showPackContent: [],
+      downloadSharedAs: ''
+    }
+  },
+  computed: {
+    isDesktop() {
+      return this.$store.state.app.device === 'desktop'
+    },
+    isMobile() {
+      return this.$store.state.app.device === 'mobile'
+    },
+    isTablet() {
+      return this.$store.state.app.device === 'tablet'
+    },
+    labelWidth() {
+      if (this.isMobile) {
+        return '90px'
+      } else if (this.isTablet) {
+        return '120px'
+      } else {
+        return '120px'
+      }
+    },
+    loadRemotePack() {
+      return this.$store.state.emojiPacks.activeCollapseItems.includes(this.name)
+    },
+    share: {
+      get() { return this.pack.pack['share-files'] },
+      set(value) {
+        this.$store.dispatch(
+          'UpdateLocalPackVal',
+          { name: this.name, key: 'share-files', value }
+        )
+      }
+    },
+    homepage: {
+      get() { return this.pack.pack['homepage'] },
+      set(value) {
+        this.$store.dispatch(
+          'UpdateLocalPackVal',
+          { name: this.name, key: 'homepage', value }
+        )
+      }
+    },
+    description: {
+      get() { return this.pack.pack['description'] },
+      set(value) {
+        this.$store.dispatch(
+          'UpdateLocalPackVal',
+          { name: this.name, key: 'description', value }
+        )
+      }
+    },
+    license: {
+      get() { return this.pack.pack['license'] },
+      set(value) {
+        this.$store.dispatch(
+          'UpdateLocalPackVal',
+          { name: this.name, key: 'license', value }
+        )
+      }
+    },
+    fallbackSrc: {
+      get() { return this.pack.pack['fallback-src'] },
+      set(value) {
+        if (value.trim() !== '') {
+          this.$store.dispatch(
+            'UpdateLocalPackVal',
+            { name: this.name, key: 'fallback-src', value }
+          )
+        } else {
+          this.$store.dispatch(
+            'UpdateLocalPackVal',
+            { name: this.name, key: 'fallback-src', value: null }
+          )
+          this.$store.dispatch(
+            'UpdateLocalPackVal',
+            { name: this.name, key: 'fallback-src-sha256', value: null }
+          )
+        }
+      }
+    }
+  },
+  methods: {
+    downloadFromInstance(url) {
+      const instanceAddress = `${new URL(url).protocol}//${new URL(url).hostname}`
+      this.$store.dispatch(
+        'DownloadFrom',
+        { instanceAddress, packName: this.name, as: this.downloadSharedAs }
+      ).then(() => this.$store.dispatch('ReloadEmoji'))
+        .then(() => this.$store.dispatch('SetLocalEmojiPacks'))
+    }
+  }
+}
+</script>
+
+<style rel='stylesheet/scss' lang='scss'>
+.download-archive {
+  width: 250px
+}
+.download-pack-button-container {
+  width: 265px;
+  .el-link {
+    width: inherit;
+    span {
+      width: inherit;
+      .download-archive {
+        width: inherit;
+      }
+    }
+  }
+}
+.download-shared-pack {
+  display: flex;
+  margin-bottom: 10px;
+}
+.download-shared-pack-button {
+  margin-left: 10px;
+}
+.el-collapse-item__content {
+  padding-bottom: 0;
+}
+.el-collapse-item__header {
+  height: 36px;
+  font-size: 14px;
+  font-weight: 700;
+  color: #606266;
+}
+.emoji-pack-card {
+  margin-top: 5px;
+}
+.emoji-pack-metadata {
+  .el-form-item {
+    margin-bottom: 10px;
+  }
+}
+.has-background .el-collapse-item__header {
+  background: #f6f6f6;
+}
+.no-background .el-collapse-item__header {
+  background: white;
+}
+.pack-button-container {
+  margin: 0 0 18px 120px;
+}
+.save-pack-button-container {
+  margin-bottom: 8px;
+  width: 265px;
+  display: flex;
+  justify-content: space-between;
+}
+@media only screen and (max-width:480px) {
+  .delete-pack-button {
+    width: 45%;
+  }
+  .download-pack-button-container {
+    width: 100%;
+  }
+  .download-shared-pack {
+    flex-direction: column;
+  }
+  .download-shared-pack-button {
+    margin-left: 0;
+    margin-top: 10px;
+    padding: 10px;
+  }
+  .pack-button-container {
+    width: 100%;
+    margin: 0 0 22px 0;
+  }
+  .remote-pack-metadata {
+    .el-form-item__content {
+      line-height: 24px;
+      margin-top: 4px;
+    }
+  }
+  .save-pack-button {
+    width: 54%;
+  }
+  .save-pack-button-container {
+    margin-bottom: 8px;
+    width: 100%;
+    display: flex;
+    justify-content: space-between;
+    button {
+      padding: 10px 5px;
+    }
+    .el-button+.el-button {
+      margin-left: 3px;
+    }
+  }
+}
+</style>
diff --git a/src/views/emojiPacks/index.vue b/src/views/emojiPacks/index.vue
index 2757e3a4cbc4acffbdd8552bf5309dddd058a4df..8154f2542ecc8bc2a273ad4ab1e373abc8125e09 100644
--- a/src/views/emojiPacks/index.vue
+++ b/src/views/emojiPacks/index.vue
@@ -27,7 +27,7 @@
       </el-form-item>
       <el-form-item v-if="Object.keys(localPacks).length > 0" :label="$t('emoji.packs')">
         <el-collapse v-for="(pack, name) in localPacks" :key="name" v-model="activeLocalPack">
-          <emoji-pack :name="name" :pack="pack" :host="$store.getters.authHost" :is-local="true" />
+          <local-emoji-pack :name="name" :pack="pack" :host="$store.getters.authHost" :is-local="true" />
         </el-collapse>
       </el-form-item>
       <el-divider class="divider"/>
@@ -37,6 +37,7 @@
             v-model="remoteInstanceAddress"
             :placeholder="$t('emoji.remoteInstanceAddress')" />
           <el-button
+            v-loading.fullscreen.lock="fullscreenLoading"
             :disabled="remoteInstanceAddress.trim() === ''"
             class="create-pack-button"
             @click="refreshRemotePacks">
@@ -45,8 +46,8 @@
         </div>
       </el-form-item>
       <el-form-item v-if="Object.keys(remotePacks).length > 0" :label="$t('emoji.packs')">
-        <el-collapse v-for="(pack, name) in remotePacks" :key="name" v-model="activeRemotePack">
-          <emoji-pack :name="name" :pack="pack" :host="$store.getters.authHost" :is-local="false" />
+        <el-collapse v-for="(pack, name) in remotePacks" :key="name" v-model="activeRemotePack" @change="setActiveCollapseItems">
+          <remote-emoji-pack :name="name" :pack="pack" :host="$store.getters.authHost" :is-local="false" />
         </el-collapse>
       </el-form-item>
     </el-form>
@@ -54,17 +55,19 @@
 </template>
 
 <script>
-import EmojiPack from './components/EmojiPack'
+import LocalEmojiPack from './components/LocalEmojiPack'
+import RemoteEmojiPack from './components/RemoteEmojiPack'
 import i18n from '@/lang'
 
 export default {
-  components: { EmojiPack },
+  components: { LocalEmojiPack, RemoteEmojiPack },
   data() {
     return {
       remoteInstanceAddress: '',
       newPackName: '',
       activeLocalPack: [],
-      activeRemotePack: []
+      activeRemotePack: [],
+      fullscreenLoading: false
     }
   },
   computed: {
@@ -103,6 +106,13 @@ export default {
           this.$store.dispatch('ReloadEmoji')
         })
     },
+    importFromFS() {
+      this.$store.dispatch('ImportFromFS')
+        .then(() => {
+          this.$store.dispatch('SetLocalEmojiPacks')
+          this.$store.dispatch('ReloadEmoji')
+        })
+    },
     refreshLocalPacks() {
       try {
         this.$store.dispatch('SetLocalEmojiPacks')
@@ -114,8 +124,10 @@ export default {
         message: i18n.t('emoji.refreshed')
       })
     },
-    refreshRemotePacks() {
-      this.$store.dispatch('SetRemoteEmojiPacks', { remoteInstance: this.remoteInstanceAddress })
+    async refreshRemotePacks() {
+      this.fullscreenLoading = true
+      await this.$store.dispatch('SetRemoteEmojiPacks', { remoteInstance: this.remoteInstanceAddress })
+      this.fullscreenLoading = false
     },
     async reloadEmoji() {
       try {
@@ -128,12 +140,9 @@ export default {
         message: i18n.t('emoji.reloaded')
       })
     },
-    importFromFS() {
-      this.$store.dispatch('ImportFromFS')
-        .then(() => {
-          this.$store.dispatch('SetLocalEmojiPacks')
-          this.$store.dispatch('ReloadEmoji')
-        })
+    setActiveCollapseItems(activeItems) {
+      const items = Array.isArray(activeItems) ? activeItems : [activeItems]
+      this.$store.dispatch('SetActiveCollapseItems', items)
     }
   }
 }