diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2309c1bdcca7ab2b799e614944055910bb1566c3..030c85933356cdfa451e105eaee6a8977b85eaac 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - On Reports page add links to reported account and the author of the report 
 - In Notes add link to the note author's profile page 
 - In Moderation log add link to the actor's profile page
+- Support pagination of local emoji packs and files
 - Adds MRF Activity Expiration setting
 
 ### Changed
diff --git a/src/api/emojiPacks.js b/src/api/emojiPacks.js
index 61319cec44d099eb689b9d107492e49580ee3a4c..b2f980a11b858120e27e3d7f93ced17efa1ee7da 100644
--- a/src/api/emojiPacks.js
+++ b/src/api/emojiPacks.js
@@ -37,10 +37,9 @@ export async function createPack(host, token, packName) {
 export async function deleteEmojiFile(packName, shortcode, host, token) {
   return await request({
     baseURL: baseName(host),
-    url: `/api/pleroma/emoji/packs/${packName}/files`,
+    url: `/api/pleroma/emoji/packs/${packName}/files?shortcode=${shortcode}`,
     method: 'delete',
-    headers: authHeaders(token),
-    data: { shortcode }
+    headers: authHeaders(token)
   })
 }
 
@@ -53,25 +52,23 @@ export async function deletePack(host, token, packName) {
   })
 }
 
-export async function downloadFrom(host, instance, packName, as, token) {
-  if (as.trim() === '') {
-    as = null
-  }
-
+export async function downloadFrom(instanceAddress, packName, as, host, token) {
   return await request({
     baseURL: baseName(host),
     url: '/api/pleroma/emoji/packs/download',
     method: 'post',
     headers: authHeaders(token),
-    data: { url: baseName(instance), name: packName, as },
+    data: as.trim() === ''
+      ? { url: baseName(instanceAddress), name: packName }
+      : { url: baseName(instanceAddress), name: packName, as },
     timeout: 0
   })
 }
 
-export async function fetchPack(packName, host, token) {
+export async function fetchPack(packName, page, pageSize, host, token) {
   return await request({
     baseURL: baseName(host),
-    url: `/api/pleroma/emoji/packs/${packName}`,
+    url: `/api/pleroma/emoji/packs/${packName}?page=${page}&page_size=${pageSize}`,
     method: 'get',
     headers: authHeaders(token)
   })
@@ -86,11 +83,12 @@ export async function importFromFS(host, token) {
   })
 }
 
-export async function listPacks(host) {
+export async function listPacks(page, pageSize, host, token) {
   return await request({
     baseURL: baseName(host),
-    url: `/api/pleroma/emoji/packs/`,
-    method: 'get'
+    url: `/api/pleroma/emoji/packs?page=${page}&page_size=${pageSize}`,
+    method: 'get',
+    headers: authHeaders(token)
   })
 }
 
diff --git a/src/lang/en.js b/src/lang/en.js
index 2ef9a89ce1ca55dfd0154ecce67500c4cc5ed353..16ff35f2ec25b7344ec9d24c5dee50f349d1cd51 100644
--- a/src/lang/en.js
+++ b/src/lang/en.js
@@ -475,6 +475,7 @@ export default {
     specifyShortcode: 'Specify a custom shortcode',
     specifyFilename: 'Specify a custom filename',
     copy: 'Copy',
-    copyToLocalPack: 'Copy to local pack'
+    copyToLocalPack: 'Copy to local pack',
+    emptyPack: 'This emoji pack is empty'
   }
 }
diff --git a/src/store/index.js b/src/store/index.js
index 586f2b072af3620f4ac3cbf91c2fcd25ed7c5ad0..e2fcd651768e6391e2a3e6685fd69eb4660ed1a7 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -1,9 +1,11 @@
 import Vue from 'vue'
 import Vuex from 'vuex'
 import app from './modules/app'
+import emojiPacks from './modules/emojiPacks'
 import errorLog from './modules/errorLog'
-import moderationLog from './modules/moderationLog'
+import getters from './getters'
 import invites from './modules/invites'
+import moderationLog from './modules/moderationLog'
 import peers from './modules/peers'
 import permission from './modules/permission'
 import relays from './modules/relays'
@@ -14,8 +16,6 @@ import tagsView from './modules/tagsView'
 import user from './modules/user'
 import userProfile from './modules/userProfile'
 import users from './modules/users'
-import getters from './getters'
-import emojiPacks from './modules/emojiPacks.js'
 
 Vue.use(Vuex)
 
@@ -23,6 +23,7 @@ const store = new Vuex.Store({
   modules: {
     app,
     errorLog,
+    emojiPacks,
     moderationLog,
     invites,
     peers,
@@ -34,8 +35,7 @@ const store = new Vuex.Store({
     tagsView,
     user,
     userProfile,
-    users,
-    emojiPacks
+    users
   },
   getters
 })
diff --git a/src/store/modules/emojiPacks.js b/src/store/modules/emojiPacks.js
index e4748c2644a3b91864477ed082b87834a9fcfb0f..6874ed9c0240c55cdc00f042784a96127bc32604 100644
--- a/src/store/modules/emojiPacks.js
+++ b/src/store/modules/emojiPacks.js
@@ -4,6 +4,7 @@ import {
   deleteEmojiFile,
   deletePack,
   downloadFrom,
+  fetchPack,
   importFromFS,
   listPacks,
   listRemotePacks,
@@ -16,20 +17,41 @@ import { Message } from 'element-ui'
 
 import Vue from 'vue'
 
-const packs = {
+const emojiPacks = {
   state: {
-    activeCollapseItems: [],
+    activeTab: '',
+    currentFilesPage: 1,
+    currentPage: 1,
+    filesPageSize: 30,
+    localPackFilesCount: 0,
     localPacks: {},
+    localPacksCount: 0,
+    pageSize: 50,
     remoteInstance: '',
     remotePacks: {}
   },
   mutations: {
-    SET_ACTIVE_COLLAPSE_ITEMS: (state, items) => {
-      state.activeCollapseItems = items
+    SET_ACTIVE_TAB: (state, tab) => {
+      state.activeTab = tab
+    },
+    SET_FILES_COUNT: (state, count) => {
+      state.localPackFilesCount = count
+    },
+    SET_FILES_PAGE: (state, page) => {
+      state.currentFilesPage = page
     },
     SET_LOCAL_PACKS: (state, packs) => {
       state.localPacks = packs
     },
+    SET_LOCAL_PACKS_COUNT: (state, count) => {
+      state.localPacksCount = count
+    },
+    SET_PACK_FILES: (state, { name, files }) => {
+      state.localPacks = { ...state.localPacks, [name]: { ...state.localPacks[name], files }}
+    },
+    SET_PAGE: (state, page) => {
+      state.currentPage = page
+    },
     SET_REMOTE_INSTANCE: (state, name) => {
       state.remoteInstance = name
     },
@@ -67,10 +89,12 @@ const packs = {
 
       commit('UPDATE_LOCAL_PACK_FILES', { name: packName, files: result.data })
     },
-    async DeleteEmojiFile({ commit, getters }, { packName, shortcode }) {
-      let result
+    async DeleteEmojiFile({ commit, dispatch, getters, state }, { packName, shortcode }) {
+      const { [shortcode]: value, ...updatedPackFiles } = state.localPacks[packName].files
+      commit('UPDATE_LOCAL_PACK_FILES', { name: packName, files: updatedPackFiles })
+
       try {
-        result = await deleteEmojiFile(packName, shortcode, getters.authHost, getters.token)
+        await deleteEmojiFile(packName, shortcode, getters.authHost, getters.token)
       } catch (_e) {
         return
       }
@@ -79,8 +103,11 @@ const packs = {
         type: 'success',
         duration: 5 * 1000
       })
-
-      commit('UPDATE_LOCAL_PACK_FILES', { name: packName, files: result.data })
+      if (Object.keys(updatedPackFiles).length === 0 && state.currentFilesPage > 1) {
+        dispatch('FetchSinglePack', { name: packName, page: state.currentFilesPage - 1 })
+      } else {
+        dispatch('FetchSinglePack', { name: packName, page: state.currentFilesPage })
+      }
     },
     async CreatePack({ getters }, { name }) {
       await createPack(getters.authHost, getters.token, name)
@@ -89,7 +116,7 @@ const packs = {
       await deletePack(getters.authHost, getters.token, name)
     },
     async DownloadFrom({ getters }, { instanceAddress, packName, as }) {
-      const result = await downloadFrom(getters.authHost, instanceAddress, packName, as, getters.token)
+      const result = await downloadFrom(instanceAddress, packName, as, getters.authHost, getters.token)
 
       if (result.data === 'ok') {
         Message({
@@ -99,6 +126,25 @@ const packs = {
         })
       }
     },
+    async FetchLocalEmojiPacks({ commit, getters, state }, page) {
+      const { data } = await listPacks(page, state.pageSize, getters.authHost, getters.token)
+      const { packs, count } = data
+      const updatedPacks = Object.keys(packs).reduce((acc, packName) => {
+        const { files, ...pack } = packs[packName]
+        acc[packName] = pack
+        return acc
+      }, {})
+      commit('SET_LOCAL_PACKS', updatedPacks)
+      commit('SET_LOCAL_PACKS_COUNT', count)
+      commit('SET_PAGE', page)
+    },
+    async FetchSinglePack({ getters, commit, state }, { name, page }) {
+      const { data } = await fetchPack(name, page, state.filesPageSize, getters.authHost, getters.token)
+      const { files, files_count } = data
+      commit('SET_PACK_FILES', { name, files })
+      commit('SET_FILES_COUNT', files_count)
+      commit('SET_FILES_PAGE', page)
+    },
     async ImportFromFS({ getters }) {
       const result = await importFromFS(getters.authHost, getters.token)
 
@@ -136,12 +182,8 @@ 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)
+    SetActiveTab({ commit }, activeTab) {
+      commit('SET_ACTIVE_TAB', activeTab)
     },
     async SetRemoteEmojiPacks({ commit, getters }, { remoteInstance }) {
       const { data } = await listRemotePacks(getters.authHost, getters.token, remoteInstance)
@@ -152,10 +194,19 @@ const packs = {
     SetRemoteInstance({ commit }, instance) {
       commit('SET_REMOTE_INSTANCE', instance)
     },
-    async UpdateEmojiFile({ commit, getters }, { packName, shortcode, newShortcode, newFilename, force }) {
-      let result
+    async UpdateEmojiFile({ commit, dispatch, getters, state }, { packName, shortcode, newShortcode, newFilename, force }) {
+      const updatedPackFiles = Object.keys(state.localPacks[packName].files).reduce((acc, el) => {
+        if (el === shortcode) {
+          acc[newShortcode] = newFilename
+        } else {
+          acc[el] = state.localPacks[packName].files[el]
+        }
+        return acc
+      }, {})
+      commit('UPDATE_LOCAL_PACK_FILES', { name: packName, files: updatedPackFiles })
+
       try {
-        result = await updateEmojiFile(packName, shortcode, newShortcode, newFilename, force, getters.authHost, getters.token)
+        await updateEmojiFile(packName, shortcode, newShortcode, newFilename, force, getters.authHost, getters.token)
       } catch (_e) {
         return
       }
@@ -165,7 +216,7 @@ const packs = {
         duration: 5 * 1000
       })
 
-      commit('UPDATE_LOCAL_PACK_FILES', { name: packName, files: result.data })
+      dispatch('FetchSinglePack', { name: packName, page: state.currentFilesPage })
     },
     async UpdateLocalPackVal({ commit }, args) {
       commit('UPDATE_LOCAL_PACK_VAL', args)
@@ -173,4 +224,4 @@ const packs = {
   }
 }
 
-export default packs
+export default emojiPacks
diff --git a/src/views/emojiPacks/components/LocalEmojiPack.vue b/src/views/emojiPacks/components/LocalEmojiPack.vue
index 1cf4bdae0b80c9dbfe64477e9f3fd727a552ae08..8f4017567ac585219bb6289995146af78e597f6b 100644
--- a/src/views/emojiPacks/components/LocalEmojiPack.vue
+++ b/src/views/emojiPacks/components/LocalEmojiPack.vue
@@ -38,19 +38,32 @@
         </el-link>
       </div>
     </div>
-    <el-collapse v-model="showPackContent" class="contents-collapse">
+    <el-collapse v-model="showPackContent" class="contents-collapse" @change="handleChange($event, name)">
       <el-collapse-item v-if="isLocal" :title=" $t('emoji.addNewEmoji')" name="addEmoji" class="no-background">
         <new-emoji-uploader :pack-name="name"/>
       </el-collapse-item>
-      <el-collapse-item v-if="pack.files.length > 0" :title=" $t('emoji.manageEmoji')" name="manageEmoji" class="no-background">
-        <single-emoji-editor
-          v-for="[shortcode, file] in pack.files"
-          :key="shortcode"
-          :host="host"
-          :pack-name="name"
-          :shortcode="shortcode"
-          :file="file"
-          :is-local="isLocal" />
+      <el-collapse-item :title=" $t('emoji.manageEmoji')" name="manageEmoji" class="no-background">
+        <div v-if="pack.files && Object.keys(pack.files).length > 0">
+          <single-emoji-editor
+            v-for="(file, shortcode) in pack.files"
+            :key="shortcode"
+            :host="host"
+            :pack-name="name"
+            :shortcode="shortcode"
+            :file="file"
+            :is-local="isLocal" />
+        </div>
+        <span v-else class="expl">{{ $t('emoji.emptyPack') }}</span>
+        <div class="files-pagination">
+          <el-pagination
+            :total="localPackFilesCount"
+            :current-page="currentFilesPage"
+            :page-size="pageSize"
+            hide-on-single-page
+            layout="prev, pager, next"
+            @current-change="handleFilesPageChange"
+          />
+        </div>
       </el-collapse-item>
     </el-collapse>
   </el-collapse-item>
@@ -86,6 +99,12 @@ export default {
     }
   },
   computed: {
+    currentFilesPage() {
+      return this.$store.state.emojiPacks.currentFilesPage
+    },
+    currentPage() {
+      return this.$store.state.emojiPacks.currentPage
+    },
     isMobile() {
       return this.$store.state.app.device === 'mobile'
     },
@@ -101,6 +120,12 @@ export default {
         return '155px'
       }
     },
+    localPackFilesCount() {
+      return this.$store.state.emojiPacks.localPackFilesCount
+    },
+    pageSize() {
+      return this.$store.state.emojiPacks.filesPageSize
+    },
     share: {
       get() { return this.pack.pack['share-files'] },
       set(value) {
@@ -159,6 +184,9 @@ export default {
     }
   },
   methods: {
+    collapse() {
+      this.showPackContent = []
+    },
     deletePack() {
       this.$confirm('This will delete the pack, are you sure?', 'Warning', {
         confirmButtonText: 'Yes, delete the pack',
@@ -167,9 +195,24 @@ export default {
       }).then(() => {
         this.$store.dispatch('DeletePack', { name: this.name })
           .then(() => this.$store.dispatch('ReloadEmoji'))
-          .then(() => this.$store.dispatch('SetLocalEmojiPacks'))
+          .then(() => {
+            const { [this.name]: value, ...updatedPacks } = this.$store.state.emojiPacks.localPacks
+            if (Object.keys(updatedPacks).length === 0 && this.currentPage > 1) {
+              this.$store.dispatch('FetchLocalEmojiPacks', this.currentPage - 1)
+            } else {
+              this.$store.dispatch('FetchLocalEmojiPacks', this.currentPage)
+            }
+          })
       }).catch(() => {})
     },
+    handleChange(openTabs, name) {
+      if (openTabs.includes('manageEmoji')) {
+        this.$store.dispatch('FetchSinglePack', { name, page: 1 })
+      }
+    },
+    handleFilesPageChange(page) {
+      this.$store.dispatch('FetchSinglePack', { name: this.name, page })
+    },
     savePackMetadata() {
       this.$store.dispatch('SavePackMetadata', { packName: this.name })
     }
@@ -217,6 +260,10 @@ export default {
     margin-bottom: 10px;
   }
 }
+.files-pagination {
+  margin: 25px 0;
+  text-align: center;
+}
 .has-background .el-collapse-item__header {
   background: #f6f6f6;
 }
diff --git a/src/views/emojiPacks/components/RemoteEmojiPack.vue b/src/views/emojiPacks/components/RemoteEmojiPack.vue
index 3ae2af5de9bc1054e094b33dbb8d0951653048d8..a3ebe017c6404fd90e55552b78a7173b4548a7a9 100644
--- a/src/views/emojiPacks/components/RemoteEmojiPack.vue
+++ b/src/views/emojiPacks/components/RemoteEmojiPack.vue
@@ -24,7 +24,7 @@
         </el-form-item>
         <el-form-item>
           <el-link
-            v-if="pack.pack['can-download']"
+            v-if="pack.pack['can-download'] && pack.pack['fallback-src']"
             :href="pack.pack['fallback-src']"
             :underline="false"
             type="primary"
@@ -34,15 +34,18 @@
         </el-form-item>
       </el-form>
       <el-collapse v-model="showPackContent" class="contents-collapse">
-        <el-collapse-item v-if="pack.files.length > 0" :title=" $t('emoji.manageEmoji')" name="manageEmoji" class="no-background">
-          <single-emoji-editor
-            v-for="[shortcode, file] in pack.files"
-            :key="shortcode"
-            :host="host"
-            :pack-name="name"
-            :shortcode="shortcode"
-            :file="file"
-            :is-local="isLocal" />
+        <el-collapse-item :title=" $t('emoji.manageEmoji')" name="manageEmoji" class="no-background">
+          <div v-if="pack.files && Object.keys(pack.files).length > 0">
+            <single-emoji-editor
+              v-for="(file, shortcode) in pack.files"
+              :key="shortcode"
+              :host="host"
+              :pack-name="name"
+              :shortcode="shortcode"
+              :file="file"
+              :is-local="isLocal" />
+          </div>
+          <span v-else class="expl">{{ $t('emoji.emptyPack') }}</span>
         </el-collapse-item>
         <el-collapse-item :title=" $t('emoji.downloadPack')" name="downloadPack" class="no-background">
           <p>
@@ -92,6 +95,9 @@ export default {
     }
   },
   computed: {
+    currentPage() {
+      return this.$store.state.emojiPacks.currentPage
+    },
     isDesktop() {
       return this.$store.state.app.device === 'desktop'
     },
@@ -111,7 +117,7 @@ export default {
       }
     },
     loadRemotePack() {
-      return this.$store.state.emojiPacks.activeCollapseItems.includes(this.name)
+      return this.$store.state.emojiPacks.activeTab === this.name
     },
     remoteInstanceAddress() {
       return this.$store.state.emojiPacks.remoteInstance
@@ -179,7 +185,7 @@ export default {
         'DownloadFrom',
         { instanceAddress: this.remoteInstanceAddress, packName: this.name, as: this.downloadSharedAs }
       ).then(() => this.$store.dispatch('ReloadEmoji'))
-        .then(() => this.$store.dispatch('SetLocalEmojiPacks'))
+        .then(() => this.$store.dispatch('FetchLocalEmojiPacks', this.currentPage))
     }
   }
 }
diff --git a/src/views/emojiPacks/components/SingleEmojiEditor.vue b/src/views/emojiPacks/components/SingleEmojiEditor.vue
index bb82a2989079e043b90e13ecfeaee8f24d5b37c6..9a773f67fcd68737aeb17aed0d4ee1e43ce37a00 100644
--- a/src/views/emojiPacks/components/SingleEmojiEditor.vue
+++ b/src/views/emojiPacks/components/SingleEmojiEditor.vue
@@ -103,7 +103,7 @@ export default {
       return this.$store.state.emojiPacks.localPacks
     },
     remoteInstance() {
-      return new URL(this.$store.state.emojiPacks.remoteInstance).host
+      return this.$store.state.emojiPacks.remoteInstance
     }
   },
   methods: {
diff --git a/src/views/emojiPacks/index.vue b/src/views/emojiPacks/index.vue
index c9173f43570edbac694c79c952d0c2f4d56d05b2..0dd0eedc8b964336e1f3a6e9bbf6ee094c8c2bc8 100644
--- a/src/views/emojiPacks/index.vue
+++ b/src/views/emojiPacks/index.vue
@@ -6,56 +6,72 @@
     </div>
     <div class="emoji-header-container">
       <div class="emoji-packs-header-button-container">
-        <el-button type="primary" class="reload-emoji-button" @click="reloadEmoji">{{ $t('emoji.reloadEmoji') }}</el-button>
+        <el-button class="reload-emoji-button" @click="reloadEmoji">{{ $t('emoji.reloadEmoji') }}</el-button>
         <el-tooltip :content="$t('emoji.importEmojiTooltip')" effects="dark" placement="bottom" popper-class="import-pack-button">
-          <el-button type="primary" @click="importFromFS">
+          <el-button @click="importFromFS">
             {{ $t('emoji.importPacks') }}
           </el-button>
         </el-tooltip>
       </div>
     </div>
-    <el-divider class="divider"/>
-    <el-form :label-width="labelWidth" class="emoji-packs-form">
-      <el-form-item :label="$t('emoji.localPacks')">
-        <el-button type="primary" @click="refreshLocalPacks">{{ $t('emoji.refreshLocalPacks') }}</el-button>
-      </el-form-item>
-      <el-form-item :label="$t('emoji.createLocalPack')">
-        <div class="create-pack">
-          <el-input v-model="newPackName" :placeholder="$t('users.name')" />
-          <el-button
-            :disabled="newPackName.trim() === ''"
-            class="create-pack-button"
-            @click="createLocalPack">
-            {{ $t('users.create') }}
-          </el-button>
-        </div>
-      </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">
-          <local-emoji-pack :name="name" :pack="sortPack(pack)" :host="$store.getters.authHost" :is-local="true" />
-        </el-collapse>
-      </el-form-item>
-      <el-divider class="divider"/>
-      <el-form-item :label="$t('emoji.remotePacks')">
-        <div class="create-pack">
-          <el-input
-            v-model="remoteInstanceAddress"
-            :placeholder="$t('emoji.remoteInstanceAddress')" />
-          <el-button
-            v-loading.fullscreen.lock="fullscreenLoading"
-            :disabled="remoteInstanceAddress.trim() === ''"
-            class="create-pack-button"
-            @click="refreshRemotePacks">
-            {{ $t('emoji.refreshRemote') }}
-          </el-button>
+    <el-tabs v-model="activeTab" type="card" class="emoji-packs-tabs">
+      <el-tab-pane :label="$t('emoji.localPacks')" name="local">
+        <el-form :label-width="labelWidth" class="emoji-packs-form">
+          <el-form-item :label="$t('emoji.localPacks')">
+            <el-button @click="refreshLocalPacks">{{ $t('emoji.refreshLocalPacks') }}</el-button>
+          </el-form-item>
+          <el-form-item :label="$t('emoji.createLocalPack')">
+            <div class="create-pack">
+              <el-input v-model="newPackName" :placeholder="$t('users.name')" />
+              <el-button
+                :disabled="newPackName.trim() === ''"
+                class="create-pack-button"
+                @click="createLocalPack">
+                {{ $t('users.create') }}
+              </el-button>
+            </div>
+          </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" accordion @change="setActiveTab">
+              <local-emoji-pack ref="localEmojiPack" :name="name" :pack="pack" :host="$store.getters.authHost" :is-local="true" />
+            </el-collapse>
+          </el-form-item>
+        </el-form>
+        <div class="pagination">
+          <el-pagination
+            :total="localPacksCount"
+            :current-page="currentPage"
+            :page-size="pageSize"
+            hide-on-single-page
+            layout="prev, pager, next"
+            @current-change="handlePageChange"
+          />
         </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" @change="setActiveCollapseItems">
-          <remote-emoji-pack :name="name" :pack="sortPack(pack)" :host="$store.getters.authHost" :is-local="false" />
-        </el-collapse>
-      </el-form-item>
-    </el-form>
+      </el-tab-pane>
+      <el-tab-pane :label="$t('emoji.remotePacks')" name="remote">
+        <el-form :label-width="labelWidth" class="emoji-packs-form">
+          <el-form-item :label="$t('emoji.remotePacks')">
+            <div class="create-pack">
+              <el-input
+                v-model="remoteInstanceAddress"
+                :placeholder="$t('emoji.remoteInstanceAddress')" />
+              <el-button
+                v-loading.fullscreen.lock="fullscreenLoading"
+                :disabled="remoteInstanceAddress.trim() === ''"
+                class="create-pack-button"
+                @click="refreshRemotePacks">
+                {{ $t('emoji.refreshRemote') }}
+              </el-button>
+            </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" accordion @change="setActiveTab">
+              <remote-emoji-pack :name="name" :pack="pack" :host="$store.getters.authHost" :is-local="false" />
+            </el-collapse>
+          </el-form-item>
+        </el-form>
+      </el-tab-pane>
+    </el-tabs>
   </div>
 </template>
 
@@ -69,6 +85,7 @@ export default {
   components: { LocalEmojiPack, RebootButton, RemoteEmojiPack },
   data() {
     return {
+      activeTab: 'local',
       newPackName: '',
       activeLocalPack: [],
       activeRemotePack: [],
@@ -76,6 +93,9 @@ export default {
     }
   },
   computed: {
+    currentPage() {
+      return this.$store.state.emojiPacks.currentPage
+    },
     isMobile() {
       return this.$store.state.app.device === 'mobile'
     },
@@ -88,12 +108,18 @@ export default {
       } else if (this.isTablet) {
         return '180px'
       } else {
-        return '240px'
+        return '200px'
       }
     },
     localPacks() {
       return this.$store.state.emojiPacks.localPacks
     },
+    localPacksCount() {
+      return this.$store.state.emojiPacks.localPacksCount
+    },
+    pageSize() {
+      return this.$store.state.emojiPacks.pageSize
+    },
     remoteInstanceAddress: {
       get() {
         return this.$store.state.emojiPacks.remoteInstance
@@ -117,25 +143,23 @@ export default {
         .then(() => {
           this.newPackName = ''
 
-          this.$store.dispatch('SetLocalEmojiPacks')
+          this.$store.dispatch('FetchLocalEmojiPacks', this.currentPage)
           this.$store.dispatch('ReloadEmoji')
         })
     },
+    handlePageChange(page) {
+      this.$store.dispatch('FetchLocalEmojiPacks', page)
+    },
     importFromFS() {
       this.$store.dispatch('ImportFromFS')
         .then(() => {
-          this.$store.dispatch('SetLocalEmojiPacks')
+          this.$store.dispatch('FetchLocalEmojiPacks', this.currentPage)
           this.$store.dispatch('ReloadEmoji')
         })
     },
-    sortPack(pack) {
-      const orderedFiles = Object.keys(pack.files).sort((a, b) => a.localeCompare(b))
-        .map(key => [key, pack.files[key]])
-      return { ...pack, files: orderedFiles }
-    },
     refreshLocalPacks() {
       try {
-        this.$store.dispatch('SetLocalEmojiPacks')
+        this.$store.dispatch('FetchLocalEmojiPacks', this.currentPage)
       } catch (e) {
         return
       }
@@ -160,15 +184,22 @@ export default {
         message: i18n.t('emoji.reloaded')
       })
     },
-    setActiveCollapseItems(activeItems) {
-      const items = Array.isArray(activeItems) ? activeItems : [activeItems]
-      this.$store.dispatch('SetActiveCollapseItems', items)
+    setActiveTab(activeTab) {
+      this.$refs.localEmojiPack.forEach(el => el.collapse())
+      this.$store.dispatch('SetActiveTab', activeTab)
     }
   }
 }
 </script>
 
 <style rel='stylesheet/scss' lang='scss'>
+.create-pack {
+  display: flex;
+  justify-content: space-between
+}
+.create-pack-button {
+  margin-left: 10px;
+}
 .emoji-header-container {
   display: flex;
   align-items: center;
@@ -178,15 +209,8 @@ export default {
 .emoji-packs-header-button-container {
   display: flex;
 }
-.create-pack {
-  display: flex;
-  justify-content: space-between
-}
-.create-pack-button {
-  margin-left: 10px;
-}
 .emoji-packs-form {
-  margin: 0 30px;
+  margin-top: 15px;
 }
 .emoji-packs-header {
   display: flex;
@@ -194,6 +218,9 @@ export default {
   justify-content: space-between;
   margin: 10px 15px 15px 15px;
 }
+.emoji-packs-tabs {
+  margin: 0 15px 15px 15px;
+}
 .import-pack-button {
   margin-left: 10px;
   width: 30%;
@@ -208,6 +235,10 @@ h1 {
   border: 1px solid #eee;
   margin-bottom: 22px;
 }
+.pagination {
+  margin: 25px 0;
+  text-align: center;
+}
 .reboot-button {
   padding: 10px;
   margin: 0;
diff --git a/src/views/users/index.vue b/src/views/users/index.vue
index 58fad28c5db480c3a564b00a9a0d50e217e4616c..c567100958639a35a67ba57069a723cf0f9ddc76 100644
--- a/src/views/users/index.vue
+++ b/src/views/users/index.vue
@@ -95,7 +95,7 @@
         :total="usersCount"
         :current-page="currentPage"
         :page-size="pageSize"
-        background
+        hide-on-single-page
         layout="prev, pager, next"
         @current-change="handlePageChange"
       />