diff --git a/changelog/unreleased/enhancement-admin-settings-support-pagination b/changelog/unreleased/enhancement-admin-settings-support-pagination
new file mode 100644
index 00000000000..c382172697b
--- /dev/null
+++ b/changelog/unreleased/enhancement-admin-settings-support-pagination
@@ -0,0 +1,7 @@
+Enhancement: Support pagination in admin settings app
+
+We've added pagination to various lists in the admin settings app.
+So there will be a page selection at the end of the list if more than 50 items are present.
+
+https://github.com/owncloud/web/issues/9048
+https://github.com/owncloud/web/pull/9119
diff --git a/packages/web-app-admin-settings/src/components/Groups/GroupsList.vue b/packages/web-app-admin-settings/src/components/Groups/GroupsList.vue
index 95e461b81b6..79e896c8ebc 100644
--- a/packages/web-app-admin-settings/src/components/Groups/GroupsList.vue
+++ b/packages/web-app-admin-settings/src/components/Groups/GroupsList.vue
@@ -12,7 +12,7 @@
       :sort-by="sortBy"
       :sort-dir="sortDir"
       :fields="fields"
-      :data="data"
+      :data="paginatedItems"
       :highlighted="highlighted"
       :sticky="true"
       :header-position="fileListHeaderY"
@@ -28,7 +28,9 @@
           :label="$gettext('Select all groups')"
           :model-value="allGroupsSelected"
           hide-label
-          @update:model-value="$emit('toggleSelectAllGroups')"
+          @update:model-value="
+            allGroupsSelected ? $emit('unSelectAllGroups') : $emit('selectGroups', paginatedItems)
+          "
         />
       </template>
       <template #select="rowData">
@@ -93,6 +95,7 @@
         </context-menu-quick-action>
       </template>
       <template #footer>
+        <pagination :pages="paginationPages" :current-page="currentPage" />
         <div class="oc-text-nowrap oc-text-center oc-width-1-1 oc-my-s">
           <p class="oc-text-muted">{{ footerTextTotal }}</p>
           <p v-if="filterTerm" class="oc-text-muted">{{ footerTextFilter }}</p>
@@ -103,20 +106,30 @@
 </template>
 
 <script lang="ts">
-import { defineComponent, PropType, ref, unref, ComponentPublicInstance, computed } from 'vue'
+import {
+  defineComponent,
+  PropType,
+  ref,
+  unref,
+  ComponentPublicInstance,
+  computed,
+  watch
+} from 'vue'
 import Fuse from 'fuse.js'
 import Mark from 'mark.js'
-import { displayPositionedDropdown, eventBus } from 'web-pkg'
+import { displayPositionedDropdown, eventBus, SortDir } from 'web-pkg'
 import { SideBarEventTopics } from 'web-pkg/src/composables/sideBar'
 import { Group } from 'web-client/src/generated'
 import ContextMenuQuickAction from 'web-pkg/src/components/ContextActions/ContextMenuQuickAction.vue'
 import { useGettext } from 'vue3-gettext'
 import { defaultFuseOptions } from 'web-pkg/src/helpers'
 import { useFileListHeaderPosition } from 'web-pkg/src/composables'
+import Pagination from 'web-pkg/src/components/Pagination.vue'
+import { usePagination } from 'web-app-admin-settings/src/composables'
 
 export default defineComponent({
   name: 'GroupsList',
-  components: { ContextMenuQuickAction },
+  components: { ContextMenuQuickAction, Pagination },
   props: {
     groups: {
       type: Array as PropType<Group[]>,
@@ -127,11 +140,14 @@ export default defineComponent({
       required: true
     }
   },
-  emits: ['toggleSelectAllGroups', 'unSelectAllGroups', 'toggleSelectGroup'],
+  emits: ['selectGroups', 'unSelectAllGroups', 'toggleSelectGroup'],
   setup(props, { emit }) {
     const { $gettext } = useGettext()
     const { y: fileListHeaderY } = useFileListHeaderPosition('#admin-settings-app-bar')
     const contextMenuButtonRef = ref(undefined)
+    const sortBy = ref<string>('displayName')
+    const sortDir = ref<string>(SortDir.Asc)
+    const filterTerm = ref<string>('')
 
     const isGroupSelected = (group) => {
       return props.selectedGroups.some((s) => s.id === group.id)
@@ -140,6 +156,7 @@ export default defineComponent({
       emit('unSelectAllGroups')
       emit('toggleSelectGroup', group)
     }
+
     const showDetails = (group) => {
       if (!isGroupSelected(group)) {
         selectGroup(group)
@@ -183,6 +200,36 @@ export default defineComponent({
 
     const readOnlyLabel = computed(() => $gettext("This group is read-only and can't be edited"))
 
+    const filter = (groups: Group[], filterTerm: string) => {
+      if (!(filterTerm || '').trim()) {
+        return groups
+      }
+      const groupsSearchEngine = new Fuse(groups, { ...defaultFuseOptions, keys: ['displayName'] })
+      return groupsSearchEngine.search(filterTerm).map((r) => r.item)
+    }
+
+    const orderBy = (list, prop, desc) => {
+      return [...list].sort((a, b) => {
+        a = a[prop]?.toString() || ''
+        b = b[prop]?.toString() || ''
+        return desc ? b.localeCompare(a) : a.localeCompare(b)
+      })
+    }
+
+    const items = computed(() => {
+      return orderBy(
+        filter(props.groups, unref(filterTerm)),
+        unref(sortBy),
+        unref(sortDir) === SortDir.Desc
+      )
+    })
+
+    const pagination = usePagination({ items })
+
+    watch(pagination.currentPage, () => {
+      emit('unSelectAllGroups')
+    })
+
     return {
       showDetails,
       rowClicked,
@@ -192,15 +239,19 @@ export default defineComponent({
       fileListHeaderY,
       contextMenuButtonRef,
       showEditPanel,
-      readOnlyLabel
+      readOnlyLabel,
+      filterTerm,
+      sortBy,
+      sortDir,
+      items,
+      ...pagination,
+      filter,
+      orderBy
     }
   },
   data() {
     return {
-      sortBy: 'displayName',
-      sortDir: 'asc',
-      markInstance: null,
-      filterTerm: ''
+      markInstance: null
     }
   },
   computed: {
@@ -241,7 +292,7 @@ export default defineComponent({
       ]
     },
     allGroupsSelected() {
-      return this.groups.length === this.selectedGroups.length
+      return this.paginatedItems.length === this.selectedGroups.length
     },
     footerTextTotal() {
       return this.$gettext('%{groupCount} groups in total', {
@@ -250,25 +301,19 @@ export default defineComponent({
     },
     footerTextFilter() {
       return this.$gettext('%{groupCount} matching groups', {
-        groupCount: this.data.length.toString()
+        groupCount: this.items.length.toString()
       })
     },
-    data() {
-      return this.orderBy(
-        this.filter(this.groups, this.filterTerm),
-        this.sortBy,
-        this.sortDir === 'desc'
-      )
-    },
     highlighted() {
       return this.selectedGroups.map((group) => group.id)
     }
   },
   watch: {
-    filterTerm() {
+    async filterTerm() {
       if (!this.markInstance) {
         return
       }
+      await this.$router.push({ ...this.$route, query: { ...this.$route.query, page: '1' } })
       this.markInstance.unmark()
       this.markInstance.mark(this.filterTerm, {
         element: 'span',
@@ -283,20 +328,6 @@ export default defineComponent({
     })
   },
   methods: {
-    filter(groups, filterTerm) {
-      if (!(filterTerm || '').trim()) {
-        return groups
-      }
-      const groupsSearchEngine = new Fuse(groups, { ...defaultFuseOptions, keys: ['displayName'] })
-      return groupsSearchEngine.search(filterTerm).map((r) => r.item)
-    },
-    orderBy(list, prop, desc) {
-      return [...list].sort((a, b) => {
-        a = a[prop]?.toString() || ''
-        b = b[prop]?.toString() || ''
-        return desc ? b.localeCompare(a) : a.localeCompare(b)
-      })
-    },
     handleSort(event) {
       this.sortBy = event.sortBy
       this.sortDir = event.sortDir
diff --git a/packages/web-app-admin-settings/src/components/Spaces/SpacesList.vue b/packages/web-app-admin-settings/src/components/Spaces/SpacesList.vue
index 095e4a984d6..63139945f8c 100644
--- a/packages/web-app-admin-settings/src/components/Spaces/SpacesList.vue
+++ b/packages/web-app-admin-settings/src/components/Spaces/SpacesList.vue
@@ -13,7 +13,7 @@
       :sort-by="sortBy"
       :sort-dir="sortDir"
       :fields="fields"
-      :data="orderedSpaces"
+      :data="paginatedItems"
       :highlighted="highlighted"
       :sticky="true"
       :header-position="fileListHeaderY"
@@ -29,7 +29,9 @@
           :label="$gettext('Select all spaces')"
           :model-value="allSpacesSelected"
           hide-label
-          @update:model-value="$emit('toggleSelectAllSpaces')"
+          @update:model-value="
+            allSpacesSelected ? $emit('unSelectAllSpaces') : $emit('selectSpaces', paginatedItems)
+          "
         />
       </template>
       <template #select="{ item }">
@@ -105,6 +107,7 @@
         </div>
       </template>
       <template #footer>
+        <pagination :pages="paginationPages" :current-page="currentPage" />
         <div class="oc-text-nowrap oc-text-center oc-width-1-1 oc-my-s">
           <p class="oc-text-muted">{{ footerTextTotal }}</p>
           <p v-if="filterTerm" class="oc-text-muted">{{ footerTextFilter }}</p>
@@ -128,14 +131,16 @@ import { spaceRoleEditor, spaceRoleManager, spaceRoleViewer } from 'web-client/s
 import Mark from 'mark.js'
 import Fuse from 'fuse.js'
 import { useGettext } from 'vue3-gettext'
-import { eventBus } from 'web-pkg'
+import { eventBus, SortDir } from 'web-pkg'
 import { SideBarEventTopics } from 'web-pkg/src/composables/sideBar'
 import ContextMenuQuickAction from 'web-pkg/src/components/ContextActions/ContextMenuQuickAction.vue'
-import { useFileListHeaderPosition } from 'web-pkg/src/composables'
+import { useFileListHeaderPosition, useRoute, useRouter } from 'web-pkg/src/composables'
+import { usePagination } from 'web-app-admin-settings/src/composables'
+import Pagination from 'web-pkg/src/components/Pagination.vue'
 
 export default defineComponent({
   name: 'SpacesList',
-  components: { ContextMenuQuickAction },
+  components: { ContextMenuQuickAction, Pagination },
   props: {
     spaces: {
       type: Array as PropType<SpaceResource[]>,
@@ -146,18 +151,20 @@ export default defineComponent({
       required: true
     }
   },
-  emits: ['toggleSelectSpace', 'toggleSelectAllSpaces', 'unSelectAllSpaces'],
+  emits: ['toggleSelectSpace', 'selectSpaces', 'unSelectAllSpaces'],
   setup: function (props, { emit }) {
+    const router = useRouter()
+    const route = useRoute()
     const { $gettext, current: currentLanguage } = useGettext()
+
     const { y: fileListHeaderY } = useFileListHeaderPosition('#admin-settings-app-bar')
     const contextMenuButtonRef = ref(undefined)
     const sortBy = ref('name')
-    const sortDir = ref('asc')
+    const sortDir = ref(SortDir.Asc)
     const filterTerm = ref('')
     const markInstance = ref(undefined)
     const tableRef = ref(undefined)
 
-    const allSpacesSelected = computed(() => props.spaces.length === props.selectedSpaces.length)
     const highlighted = computed(() => props.selectedSpaces.map((s) => s.id))
     const footerTextTotal = computed(() => {
       return $gettext('%{spaceCount} spaces in total', {
@@ -166,7 +173,7 @@ export default defineComponent({
     })
     const footerTextFilter = computed(() => {
       return $gettext('%{spaceCount} matching spaces', {
-        spaceCount: unref(orderedSpaces).length.toString()
+        spaceCount: unref(items).length.toString()
       })
     })
 
@@ -206,9 +213,24 @@ export default defineComponent({
           : a.localeCompare(b, undefined, { numeric })
       })
     }
-    const orderedSpaces = computed(() =>
-      orderBy(filter(props.spaces, unref(filterTerm)), unref(sortBy), unref(sortDir) === 'desc')
+    const items = computed(() =>
+      orderBy(
+        filter(props.spaces, unref(filterTerm)),
+        unref(sortBy),
+        unref(sortDir) === SortDir.Desc
+      )
     )
+
+    const pagination = usePagination({ items })
+
+    watch(pagination.currentPage, () => {
+      emit('unSelectAllSpaces')
+    })
+
+    const allSpacesSelected = computed(() => {
+      return unref(pagination.paginatedItems).length === props.selectedSpaces.length
+    })
+
     const handleSort = (event) => {
       sortBy.value = event.sortBy
       sortDir.value = event.sortDir
@@ -347,11 +369,12 @@ export default defineComponent({
       })
     })
 
-    watch(filterTerm, () => {
+    watch(filterTerm, async () => {
       const instance = unref(markInstance)
       if (!instance) {
         return
       }
+      await router.push({ ...unref(route), query: { ...unref(route).query, page: '1' } })
       instance.unmark()
       instance.mark(unref(filterTerm), {
         element: 'span',
@@ -417,7 +440,6 @@ export default defineComponent({
       getMemberCount,
       getSelectSpaceLabel,
       handleSort,
-      orderedSpaces,
       fileClicked,
       isSpaceSelected,
       contextMenuButtonRef,
@@ -425,7 +447,9 @@ export default defineComponent({
       showContextMenuOnRightClick,
       spaceDetailsLabel,
       showDetailsForSpace,
-      fileListHeaderY
+      fileListHeaderY,
+      items,
+      ...pagination
     }
   }
 })
diff --git a/packages/web-app-admin-settings/src/components/Users/UsersList.vue b/packages/web-app-admin-settings/src/components/Users/UsersList.vue
index 4302ad70990..6776f33eaa7 100644
--- a/packages/web-app-admin-settings/src/components/Users/UsersList.vue
+++ b/packages/web-app-admin-settings/src/components/Users/UsersList.vue
@@ -20,7 +20,7 @@
       :sort-by="sortBy"
       :sort-dir="sortDir"
       :fields="fields"
-      :data="data"
+      :data="paginatedItems"
       :highlighted="highlighted"
       :sticky="true"
       :header-position="fileListHeaderY"
@@ -36,7 +36,9 @@
           :label="$gettext('Select all users')"
           :model-value="allUsersSelected"
           hide-label
-          @update:model-value="$emit('toggleSelectAllUsers')"
+          @update:model-value="
+            allUsersSelected ? $emit('unSelectAllUsers') : $emit('selectUsers', paginatedItems)
+          "
         />
       </template>
       <template #select="{ item }">
@@ -97,6 +99,7 @@
         </context-menu-quick-action>
       </template>
       <template #footer>
+        <pagination :pages="paginationPages" :current-page="currentPage" />
         <div class="oc-text-nowrap oc-text-center oc-width-1-1 oc-my-s">
           <p class="oc-text-muted">{{ footerTextTotal }}</p>
           <p v-if="filterTerm" class="oc-text-muted">{{ footerTextFilter }}</p>
@@ -107,19 +110,23 @@
 </template>
 
 <script lang="ts">
-import { defineComponent, PropType, ref, unref, ComponentPublicInstance } from 'vue'
+import { useGettext } from 'vue3-gettext'
+import { defineComponent, PropType, ref, unref, ComponentPublicInstance, watch } from 'vue'
 import Fuse from 'fuse.js'
 import Mark from 'mark.js'
-import { defaultFuseOptions, displayPositionedDropdown, eventBus } from 'web-pkg'
+import { defaultFuseOptions, displayPositionedDropdown, eventBus, SortDir } from 'web-pkg'
 import { SideBarEventTopics } from 'web-pkg/src/composables/sideBar'
 import { AppRole, User } from 'web-client/src/generated'
 import ContextMenuQuickAction from 'web-pkg/src/components/ContextActions/ContextMenuQuickAction.vue'
 import NoContentMessage from 'web-pkg/src/components/NoContentMessage.vue'
 import { useFileListHeaderPosition } from 'web-pkg/src/composables'
+import Pagination from 'web-pkg/src/components/Pagination.vue'
+import { usePagination } from 'web-app-admin-settings/src/composables'
+import { computed } from 'vue'
 
 export default defineComponent({
   name: 'UsersList',
-  components: { ContextMenuQuickAction, NoContentMessage },
+  components: { ContextMenuQuickAction, NoContentMessage, Pagination },
   props: {
     users: {
       type: Array as PropType<User[]>,
@@ -134,13 +141,20 @@ export default defineComponent({
       required: true
     }
   },
-  emits: ['unSelectAllUsers', 'toggleSelectAllUsers', 'toggleSelectUser'],
+  emits: ['unSelectAllUsers', 'selectUsers', 'toggleSelectUser'],
   setup(props, { emit }) {
+    const { $gettext } = useGettext()
+
     const contextMenuButtonRef = ref(undefined)
+    const filterTerm = ref<string>('')
+    const sortBy = ref<string>('onPremisesSamAccountName')
+    const sortDir = ref<string>(SortDir.Asc)
     const { y: fileListHeaderY } = useFileListHeaderPosition('#admin-settings-app-bar')
+
     const isUserSelected = (user) => {
       return props.selectedUsers.some((s) => s.id === user.id)
     }
+
     const selectUser = (user) => {
       emit('unSelectAllUsers')
       emit('toggleSelectUser', user)
@@ -195,6 +209,64 @@ export default defineComponent({
       displayPositionedDropdown(dropdown._tippy, event, unref(contextMenuButtonRef))
     }
 
+    const filter = (users: User[], filterTerm: string) => {
+      if (!(filterTerm || '').trim()) {
+        return users
+      }
+      const usersSearchEngine = new Fuse(users, {
+        ...defaultFuseOptions,
+        keys: ['displayName', 'mail', 'onPremisesSamAccountName', 'role.displayName']
+      })
+
+      return usersSearchEngine.search(filterTerm).map((r) => r.item)
+    }
+
+    const getRoleDisplayNameByUser = (user: User) => {
+      const assignedRole = user.appRoleAssignments[0]
+
+      return (
+        $gettext(
+          props.roles.find((role) => role.id === assignedRole?.appRoleId)?.displayName || ''
+        ) || '-'
+      )
+    }
+
+    const orderBy = (list, prop, desc) => {
+      return [...list].sort((user1, user2) => {
+        let a, b
+
+        switch (prop) {
+          case 'role':
+            a = getRoleDisplayNameByUser(user1)
+            b = getRoleDisplayNameByUser(user2)
+            break
+          case 'accountEnabled':
+            a = ('accountEnabled' in user1 ? user1.accountEnabled : true).toString()
+            b = ('accountEnabled' in user2 ? user2.accountEnabled : true).toString()
+            break
+          default:
+            a = user1[prop] || ''
+            b = user2[prop] || ''
+        }
+
+        return desc ? b.localeCompare(a) : a.localeCompare(b)
+      })
+    }
+
+    const items = computed(() => {
+      return orderBy(
+        filter(props.users, unref(filterTerm)),
+        unref(sortBy),
+        unref(sortDir) === SortDir.Desc
+      )
+    })
+
+    const pagination = usePagination({ items })
+
+    watch(pagination.currentPage, () => {
+      emit('unSelectAllUsers')
+    })
+
     return {
       showDetails,
       showEditPanel,
@@ -204,20 +276,25 @@ export default defineComponent({
       contextMenuButtonRef,
       showContextMenuOnBtnClick,
       showContextMenuOnRightClick,
-      fileListHeaderY
+      fileListHeaderY,
+      getRoleDisplayNameByUser,
+      items,
+      filterTerm,
+      sortBy,
+      sortDir,
+      ...pagination,
+      filter,
+      orderBy
     }
   },
   data() {
     return {
-      sortBy: 'onPremisesSamAccountName',
-      sortDir: 'asc',
-      markInstance: null,
-      filterTerm: ''
+      markInstance: null
     }
   },
   computed: {
     allUsersSelected() {
-      return this.users.length === this.selectedUsers.length
+      return this.paginatedItems.length === this.selectedUsers.length
     },
     footerTextTotal() {
       return this.$gettext('%{userCount} users in total', {
@@ -226,7 +303,7 @@ export default defineComponent({
     },
     footerTextFilter() {
       return this.$gettext('%{userCount} matching users', {
-        userCount: this.data.length.toString()
+        userCount: this.items.length.toString()
       })
     },
     fields() {
@@ -280,78 +357,33 @@ export default defineComponent({
         }
       ]
     },
-    data() {
-      return this.orderBy(
-        this.filter(this.users, this.filterTerm),
-        this.sortBy,
-        this.sortDir === 'desc'
-      )
-    },
     highlighted() {
       return this.selectedUsers.map((user) => user.id)
     }
   },
   watch: {
-    filterTerm() {
-      if (this.$refs.tableRef) {
-        this.markInstance = new Mark((this.$refs.tableRef as ComponentPublicInstance).$el)
-        this.markInstance.unmark()
-        this.markInstance.mark(this.filterTerm, {
-          element: 'span',
-          className: 'highlight-mark',
-          exclude: ['th *', 'tfoot *']
-        })
+    async filterTerm() {
+      if (!this.$refs.tableRef) {
+        return
       }
+
+      await this.$router.push({ ...this.$route, query: { ...this.$route.query, page: '1' } })
+      this.markInstance = new Mark((this.$refs.tableRef as ComponentPublicInstance).$el)
+      this.markInstance.unmark()
+      this.markInstance.mark(this.filterTerm, {
+        element: 'span',
+        className: 'highlight-mark',
+        exclude: ['th *', 'tfoot *']
+      })
     }
   },
   methods: {
-    filter(users, filterTerm) {
-      if (!(filterTerm || '').trim()) {
-        return users
-      }
-      const usersSearchEngine = new Fuse(users, {
-        ...defaultFuseOptions,
-        keys: ['displayName', 'mail', 'onPremisesSamAccountName', 'role.displayName']
-      })
-
-      return usersSearchEngine.search(filterTerm).map((r) => r.item)
-    },
-    orderBy(list, prop, desc) {
-      return [...list].sort((user1, user2) => {
-        let a, b
-
-        switch (prop) {
-          case 'role':
-            a = this.getRoleDisplayNameByUser(user1)
-            b = this.getRoleDisplayNameByUser(user2)
-            break
-          case 'accountEnabled':
-            a = ('accountEnabled' in user1 ? user1.accountEnabled : true).toString()
-            b = ('accountEnabled' in user2 ? user2.accountEnabled : true).toString()
-            break
-          default:
-            a = user1[prop] || ''
-            b = user2[prop] || ''
-        }
-
-        return desc ? b.localeCompare(a) : a.localeCompare(b)
-      })
-    },
     handleSort(event) {
       this.sortBy = event.sortBy
       this.sortDir = event.sortDir
     },
     getSelectUserLabel(user) {
       return this.$gettext('Select %{ user }', { user: user.displayName }, true)
-    },
-    getRoleDisplayNameByUser(user) {
-      const assignedRole = user.appRoleAssignments[0]
-
-      return (
-        this.$gettext(
-          this.roles.find((role) => role.id === assignedRole?.appRoleId)?.displayName || ''
-        ) || '-'
-      )
     }
   }
 })
diff --git a/packages/web-app-admin-settings/src/composables/index.ts b/packages/web-app-admin-settings/src/composables/index.ts
new file mode 100644
index 00000000000..444987e2db2
--- /dev/null
+++ b/packages/web-app-admin-settings/src/composables/index.ts
@@ -0,0 +1,2 @@
+export * from './actions'
+export * from './usePagination'
diff --git a/packages/web-app-admin-settings/src/composables/usePagination.ts b/packages/web-app-admin-settings/src/composables/usePagination.ts
new file mode 100644
index 00000000000..37754214fec
--- /dev/null
+++ b/packages/web-app-admin-settings/src/composables/usePagination.ts
@@ -0,0 +1,44 @@
+import { computed, Ref, unref } from 'vue'
+import { queryItemAsString, useRouteQuery, useRouteQueryPersisted } from 'web-pkg/src'
+
+export const usePagination = ({
+  items
+}: {
+  items: Ref<any[]>
+}): {
+  currentPage: Ref<number>
+  itemsPerPage: Ref<number>
+  paginationPages: Ref<number>
+  paginatedItems: Ref<any[]>
+} => {
+  const itemsPerPageQuery = useRouteQueryPersisted({
+    name: 'admin-settings-items-per-page',
+    defaultValue: '50'
+  })
+  const pageQuery = useRouteQuery('page', '1')
+
+  const currentPage = computed(() => {
+    return parseInt(queryItemAsString(unref(pageQuery)))
+  })
+
+  const itemsPerPage = computed(() => {
+    return parseInt(queryItemAsString(unref(itemsPerPageQuery)))
+  })
+
+  const paginationPages = computed(() => {
+    return Math.ceil(unref(items).length / unref(itemsPerPage))
+  })
+
+  const paginatedItems = computed(() => {
+    const startIndex = (unref(currentPage) - 1) * unref(itemsPerPage)
+    const endIndex = startIndex + unref(itemsPerPage)
+    return unref(items).slice(startIndex, endIndex)
+  })
+
+  return {
+    currentPage,
+    itemsPerPage,
+    paginatedItems,
+    paginationPages
+  }
+}
diff --git a/packages/web-app-admin-settings/src/views/Groups.vue b/packages/web-app-admin-settings/src/views/Groups.vue
index 6fd699c6db5..03b3455f1e8 100644
--- a/packages/web-app-admin-settings/src/views/Groups.vue
+++ b/packages/web-app-admin-settings/src/views/Groups.vue
@@ -50,7 +50,7 @@
             :groups="groups"
             :selected-groups="selectedGroups"
             @toggle-select-group="toggleSelectGroup"
-            @toggle-select-all-groups="toggleSelectAllGroups"
+            @select-groups="selectGroups"
             @un-select-all-groups="unselectAllGroups"
           >
             <template #contextMenu>
@@ -160,11 +160,6 @@ export default defineComponent({
         }
       ]
     },
-
-    allGroupsSelected() {
-      return this.groups.length === this.selectedGroups.length
-    },
-
     sideBarAvailablePanels() {
       return [
         {
@@ -205,11 +200,8 @@ export default defineComponent({
   methods: {
     ...mapActions(['showMessage']),
 
-    toggleSelectAllGroups() {
-      if (this.allGroupsSelected) {
-        return (this.selectedGroups = [])
-      }
-      this.selectedGroups = [...this.groups]
+    selectGroups(groups) {
+      this.selectedGroups = [...groups]
     },
     toggleSelectGroup(toggledGroup) {
       const isGroupSelected = this.selectedGroups.find((group) => group.id === toggledGroup.id)
diff --git a/packages/web-app-admin-settings/src/views/Spaces.vue b/packages/web-app-admin-settings/src/views/Spaces.vue
index c460285997b..9853d55abe6 100644
--- a/packages/web-app-admin-settings/src/views/Spaces.vue
+++ b/packages/web-app-admin-settings/src/views/Spaces.vue
@@ -58,7 +58,7 @@
             :class="{ 'spaces-table-squashed': sideBarOpen }"
             :selected-spaces="selectedSpaces"
             @toggle-select-space="toggleSelectSpace"
-            @toggle-select-all-spaces="toggleSelectAllSpaces"
+            @select-spaces="selectSpaces"
             @un-select-all-spaces="unselectAllSpaces"
           >
             <template #contextMenu>
@@ -162,13 +162,8 @@ export default defineComponent({
       }
     ])
 
-    const allSpacesSelected = computed(() => unref(spaces).length === unref(selectedSpaces).length)
-    const toggleSelectAllSpaces = () => {
-      if (unref(allSpacesSelected)) {
-        selectedSpaces.value = []
-        return
-      }
-      selectedSpaces.value = [...unref(spaces)]
+    const selectSpaces = (paginatedSpaces) => {
+      selectedSpaces.value = [...paginatedSpaces]
     }
 
     const toggleSelectSpace = (toggledSpace) => {
@@ -292,7 +287,7 @@ export default defineComponent({
       selectedSpaces,
       sideBarAvailablePanels,
       template,
-      toggleSelectAllSpaces,
+      selectSpaces,
       toggleSelectSpace,
       unselectAllSpaces,
       quotaModalIsOpen,
diff --git a/packages/web-app-admin-settings/src/views/Users.vue b/packages/web-app-admin-settings/src/views/Users.vue
index 3f14bd1896f..4d31eee63c8 100644
--- a/packages/web-app-admin-settings/src/views/Users.vue
+++ b/packages/web-app-admin-settings/src/views/Users.vue
@@ -49,7 +49,7 @@
             :class="{ 'users-table-squashed': sideBarOpen }"
             :selected-users="selectedUsers"
             @toggle-select-user="toggleSelectUser"
-            @toggle-select-all-users="toggleSelectAllUsers"
+            @select-users="selectUsers"
             @un-select-all-users="unselectAllUsers"
           >
             <template #contextMenu>
@@ -164,7 +164,9 @@ import {
   useCapabilitySpacesMaxQuota,
   useClientService,
   useLoadingService,
+  useRoute,
   useRouteQuery,
+  useRouter,
   useStore
 } from 'web-pkg/src/composables'
 import { computed, defineComponent, ref, onBeforeUnmount, onMounted, unref, watch } from 'vue'
@@ -208,6 +210,8 @@ export default defineComponent({
   },
   setup() {
     const { $gettext, $ngettext } = useGettext()
+    const router = useRouter()
+    const route = useRoute()
     const store = useStore()
     const accessToken = useAccessToken({ store })
     const clientService = useClientService()
@@ -338,17 +342,23 @@ export default defineComponent({
       Object.assign(user, data)
     })
 
+    const resetPagination = () => {
+      return router.push({ ...unref(route), query: { ...unref(route).query, page: '1' } })
+    }
+
     const filterGroups = (groups) => {
       filters.groups.ids.value = groups.map((g) => g.id)
       loadUsersTask.perform()
       selectedUsers.value = []
       additionalUserDataLoadedForUserIds.value = []
+      return resetPagination()
     }
     const filterRoles = (roles) => {
       filters.roles.ids.value = roles.map((r) => r.id)
       loadUsersTask.perform()
       selectedUsers.value = []
       additionalUserDataLoadedForUserIds.value = []
+      return resetPagination()
     }
 
     const selectedPersonalDrives = ref([])
@@ -639,11 +649,6 @@ export default defineComponent({
         }
       ]
     },
-
-    allUsersSelected() {
-      return this.users.length === this.selectedUsers.length
-    },
-
     sideBarAvailablePanels() {
       return [
         {
@@ -680,11 +685,8 @@ export default defineComponent({
     ...mapActions(['showMessage']),
     ...mapMutations('runtime/spaces', ['UPDATE_SPACE_FIELD']),
 
-    toggleSelectAllUsers() {
-      if (this.allUsersSelected) {
-        return (this.selectedUsers = [])
-      }
-      this.selectedUsers = this.users
+    selectUsers(users) {
+      this.selectedUsers = users
     },
     toggleSelectUser(toggledUser) {
       const isUserSelected = this.selectedUsers.find((user) => user.id === toggledUser.id)
diff --git a/packages/web-app-admin-settings/tests/unit/components/Groups/GroupsList.spec.ts b/packages/web-app-admin-settings/tests/unit/components/Groups/GroupsList.spec.ts
index 06b1446f58a..269ef50ad43 100644
--- a/packages/web-app-admin-settings/tests/unit/components/Groups/GroupsList.spec.ts
+++ b/packages/web-app-admin-settings/tests/unit/components/Groups/GroupsList.spec.ts
@@ -1,6 +1,6 @@
 import GroupsList from '../../../../src/components/Groups/GroupsList.vue'
-import { defaultPlugins, mount, shallowMount } from 'web-test-helpers'
-import { displayPositionedDropdown, eventBus } from 'web-pkg'
+import { defaultComponentMocks, defaultPlugins, mount, shallowMount } from 'web-test-helpers'
+import { displayPositionedDropdown, eventBus, queryItemAsString } from 'web-pkg'
 import { SideBarEventTopics } from 'web-pkg/src/composables/sideBar'
 
 const getGroupMocks = () => [
@@ -12,6 +12,7 @@ jest.mock('web-pkg/src/helpers', () => ({
   ...jest.requireActual('web-pkg/src/helpers'),
   displayPositionedDropdown: jest.fn()
 }))
+jest.mock('web-pkg/src/composables/appDefaults')
 
 describe('GroupsList', () => {
   describe('method "orderBy"', () => {
@@ -86,6 +87,10 @@ describe('GroupsList', () => {
 })
 
 function getWrapper({ mountType = shallowMount, props = {} } = {}) {
+  jest.mocked(queryItemAsString).mockImplementationOnce(() => '1')
+  jest.mocked(queryItemAsString).mockImplementationOnce(() => '100')
+  const mocks = defaultComponentMocks()
+
   return {
     wrapper: mountType(GroupsList, {
       props: {
@@ -96,6 +101,7 @@ function getWrapper({ mountType = shallowMount, props = {} } = {}) {
       },
       global: {
         plugins: [...defaultPlugins()],
+        mocks,
         stubs: {
           OcCheckbox: true
         }
diff --git a/packages/web-app-admin-settings/tests/unit/components/Spaces/SpacesList.spec.ts b/packages/web-app-admin-settings/tests/unit/components/Spaces/SpacesList.spec.ts
index e2d67a431ea..cb9974aa674 100644
--- a/packages/web-app-admin-settings/tests/unit/components/Spaces/SpacesList.spec.ts
+++ b/packages/web-app-admin-settings/tests/unit/components/Spaces/SpacesList.spec.ts
@@ -1,6 +1,6 @@
 import SpacesList from '../../../../src/components/Spaces/SpacesList.vue'
-import { defaultPlugins, mount, shallowMount } from 'web-test-helpers'
-import { eventBus } from 'web-pkg'
+import { defaultComponentMocks, defaultPlugins, mount, shallowMount } from 'web-test-helpers'
+import { eventBus, queryItemAsString } from 'web-pkg'
 import { displayPositionedDropdown } from 'web-pkg/src/helpers'
 import { SideBarEventTopics } from 'web-pkg/src/composables/sideBar'
 import { nextTick } from 'vue'
@@ -54,6 +54,7 @@ jest.mock('web-pkg/src/helpers', () => ({
   ...jest.requireActual('web-pkg/src/helpers'),
   displayPositionedDropdown: jest.fn()
 }))
+jest.mock('web-pkg/src/composables/appDefaults')
 
 describe('SpacesList', () => {
   it('should render all spaces in a table', () => {
@@ -94,7 +95,7 @@ describe('SpacesList', () => {
     const { wrapper } = getWrapper({ spaces: spaceMocks })
     wrapper.vm.filterTerm = 'Another'
     await nextTick()
-    expect(wrapper.vm.orderedSpaces).toEqual([spaceMocks[1]])
+    expect(wrapper.vm.items).toEqual([spaceMocks[1]])
   })
   it('should show the context menu on right click', async () => {
     const spyDisplayPositionedDropdown = jest.mocked(displayPositionedDropdown)
@@ -117,6 +118,10 @@ describe('SpacesList', () => {
 })
 
 function getWrapper({ mountType = mount, spaces = [], selectedSpaces = [] } = {}) {
+  jest.mocked(queryItemAsString).mockImplementationOnce(() => '1')
+  jest.mocked(queryItemAsString).mockImplementationOnce(() => '100')
+  const mocks = defaultComponentMocks()
+
   return {
     wrapper: mountType(SpacesList, {
       props: {
@@ -126,6 +131,7 @@ function getWrapper({ mountType = mount, spaces = [], selectedSpaces = [] } = {}
       },
       global: {
         plugins: [...defaultPlugins()],
+        mocks,
         stubs: {
           OcCheckbox: true
         }
diff --git a/packages/web-app-admin-settings/tests/unit/components/Spaces/__snapshots__/SpacesList.spec.ts.snap b/packages/web-app-admin-settings/tests/unit/components/Spaces/__snapshots__/SpacesList.spec.ts.snap
index cf25ad4c56d..ec82abe3028 100644
--- a/packages/web-app-admin-settings/tests/unit/components/Spaces/__snapshots__/SpacesList.spec.ts.snap
+++ b/packages/web-app-admin-settings/tests/unit/components/Spaces/__snapshots__/SpacesList.spec.ts.snap
@@ -151,6 +151,7 @@ exports[`SpacesList should render all spaces in a table 1`] = `
       <tr class="oc-table-footer-row">
         <td class="oc-table-footer-cell" colspan="11">
           <!-- @slot Footer of the table -->
+          <!--v-if-->
           <div class="oc-text-nowrap oc-text-center oc-width-1-1 oc-my-s">
             <p class="oc-text-muted">1 spaces in total</p>
             <!--v-if-->
diff --git a/packages/web-app-admin-settings/tests/unit/components/Users/UsersList.spec.ts b/packages/web-app-admin-settings/tests/unit/components/Users/UsersList.spec.ts
index 376dbd6a21b..070bf3f27d3 100644
--- a/packages/web-app-admin-settings/tests/unit/components/Users/UsersList.spec.ts
+++ b/packages/web-app-admin-settings/tests/unit/components/Users/UsersList.spec.ts
@@ -1,6 +1,6 @@
 import UsersList from '../../../../src/components/Users/UsersList.vue'
-import { defaultPlugins, mount, shallowMount } from 'web-test-helpers'
-import { displayPositionedDropdown, eventBus } from 'web-pkg'
+import { defaultComponentMocks, defaultPlugins, mount, shallowMount } from 'web-test-helpers'
+import { displayPositionedDropdown, eventBus, queryItemAsString } from 'web-pkg'
 import { SideBarEventTopics } from 'web-pkg/src/composables/sideBar'
 
 const getUserMocks = () => [{ id: '1', displayName: 'jan' }]
@@ -8,6 +8,7 @@ jest.mock('web-pkg/src/helpers', () => ({
   ...jest.requireActual('web-pkg/src/helpers'),
   displayPositionedDropdown: jest.fn()
 }))
+jest.mock('web-pkg/src/composables/appDefaults')
 
 describe('UsersList', () => {
   describe('computed method "allUsersSelected"', () => {
@@ -142,6 +143,9 @@ describe('UsersList', () => {
 })
 
 function getWrapper({ mountType = shallowMount, props = {} } = {}) {
+  jest.mocked(queryItemAsString).mockImplementationOnce(() => '1')
+  jest.mocked(queryItemAsString).mockImplementationOnce(() => '100')
+  const mocks = defaultComponentMocks()
   return {
     wrapper: mountType(UsersList, {
       props: {
@@ -170,6 +174,7 @@ function getWrapper({ mountType = shallowMount, props = {} } = {}) {
       },
       global: {
         plugins: [...defaultPlugins()],
+        mocks,
         stubs: {
           OcCheckbox: true
         }
diff --git a/packages/web-app-admin-settings/tests/unit/composables/usePagination.spec.ts b/packages/web-app-admin-settings/tests/unit/composables/usePagination.spec.ts
new file mode 100644
index 00000000000..d4720423c60
--- /dev/null
+++ b/packages/web-app-admin-settings/tests/unit/composables/usePagination.spec.ts
@@ -0,0 +1,49 @@
+import { ref, unref } from 'vue'
+import { usePagination } from 'web-app-admin-settings/src/composables'
+import { queryItemAsString } from 'web-pkg/src'
+import { getComposableWrapper } from 'web-test-helpers'
+
+jest.mock('web-pkg/src/composables/appDefaults')
+jest.mock('web-pkg/src/composables/router')
+
+describe('usePagination', () => {
+  describe('paginatedItems', () => {
+    const items = [1, 2, 3, 4, 5, 6]
+
+    it.each([
+      { currentPage: 1, itemsPerPage: 100, expected: [1, 2, 3, 4, 5, 6] },
+      { currentPage: 1, itemsPerPage: 2, expected: [1, 2] },
+      { currentPage: 2, itemsPerPage: 2, expected: [3, 4] }
+    ])('returns proper paginated items', ({ currentPage, itemsPerPage, expected }) => {
+      getWrapper({
+        setup: ({ paginatedItems }) => {
+          expect(unref(paginatedItems)).toEqual(expected)
+        },
+        items,
+        currentPage,
+        itemsPerPage
+      })
+    })
+  })
+})
+
+function getWrapper({
+  setup,
+  items,
+  currentPage,
+  itemsPerPage
+}: {
+  setup: (instance: ReturnType<typeof usePagination>) => void
+  items: any[]
+  currentPage: number
+  itemsPerPage: number
+}) {
+  jest.mocked(queryItemAsString).mockImplementationOnce(() => currentPage.toString())
+  jest.mocked(queryItemAsString).mockImplementationOnce(() => itemsPerPage.toString())
+  return {
+    wrapper: getComposableWrapper(() => {
+      const instance = usePagination({ items: ref(items) })
+      setup(instance)
+    })
+  }
+}
diff --git a/packages/web-app-admin-settings/tests/unit/views/Groups.spec.ts b/packages/web-app-admin-settings/tests/unit/views/Groups.spec.ts
index 278ec07f048..7fc92b4f6e2 100644
--- a/packages/web-app-admin-settings/tests/unit/views/Groups.spec.ts
+++ b/packages/web-app-admin-settings/tests/unit/views/Groups.spec.ts
@@ -1,6 +1,6 @@
 import Groups from '../../../src/views/Groups.vue'
 import { mockAxiosResolve, mockAxiosReject } from 'web-test-helpers/src/mocks'
-import { mockDeep } from 'jest-mock-extended'
+import { mock, mockDeep } from 'jest-mock-extended'
 import { ClientService, eventBus } from 'web-pkg/src'
 import {
   createStore,
@@ -9,6 +9,7 @@ import {
   defaultStoreMockOptions,
   mount
 } from 'web-test-helpers'
+import { Group } from 'web-client/src/generated'
 
 const selectors = { batchActionsStub: 'batch-actions-stub' }
 const getClientServiceMock = () => {
@@ -118,25 +119,6 @@ describe('Groups view', () => {
     })
   })
 
-  describe('computed method "allGroupsSelected"', () => {
-    it('should be true if every group is selected', async () => {
-      const { wrapper } = getWrapper()
-      wrapper.vm.selectedGroups = [{ id: '1' }]
-      await wrapper.vm.loadResourcesTask.last
-      expect(wrapper.vm.allGroupsSelected).toBeTruthy()
-    })
-    it('should be false if not every group is selected', async () => {
-      const clientService = getClientServiceMock()
-      clientService.graphAuthenticated.groups.listGroups.mockImplementation(() =>
-        mockAxiosResolve({ value: [{ id: '1' }, { id: '2' }] })
-      )
-      const { wrapper } = getWrapper({ clientService })
-      wrapper.vm.selectedGroups = [{ id: '1' }]
-      await wrapper.vm.loadResourcesTask.last
-      expect(wrapper.vm.allGroupsSelected).toBeFalsy()
-    })
-  })
-
   describe('batch actions', () => {
     it('do not display when no group selected', async () => {
       const { wrapper } = getWrapper()
@@ -153,7 +135,7 @@ describe('Groups view', () => {
     it('display when more than one groups selected', async () => {
       const { wrapper } = getWrapper()
       await wrapper.vm.loadResourcesTask.last
-      wrapper.vm.toggleSelectAllGroups()
+      wrapper.vm.selectGroups([mock<Group>({ groupTypes: [] }), mock<Group>({ groupTypes: [] })])
       await wrapper.vm.$nextTick()
       expect(wrapper.find(selectors.batchActionsStub).exists()).toBeTruthy()
     })
diff --git a/packages/web-app-admin-settings/tests/unit/views/Spaces.spec.ts b/packages/web-app-admin-settings/tests/unit/views/Spaces.spec.ts
index 97d0ac526cb..9d48f66f14c 100644
--- a/packages/web-app-admin-settings/tests/unit/views/Spaces.spec.ts
+++ b/packages/web-app-admin-settings/tests/unit/views/Spaces.spec.ts
@@ -46,23 +46,13 @@ describe('Spaces view', () => {
     expect(wrapper.find(selectors.noContentMessageStub).exists()).toBeTruthy()
   })
   describe('toggle selection', () => {
-    describe('toggleSelectAllSpaces method', () => {
+    describe('selectSpaces method', () => {
       it('selects all spaces', async () => {
-        const spaces = [{ name: 'Some Space' }]
+        const spaces = [{ name: 'Some Space' }, { name: 'Some other Space' }]
         const { wrapper } = getWrapper({ spaces })
         await wrapper.vm.loadResourcesTask.last
-        wrapper.vm.toggleSelectAllSpaces()
-        expect(wrapper.vm.selectedSpaces).toEqual(
-          expect.arrayContaining([expect.objectContaining({ name: spaces[0].name })])
-        )
-      })
-      it('de-selects all selected spaces', async () => {
-        const spaces = [{ name: 'Some Space' }]
-        const { wrapper } = getWrapper({ spaces })
-        await wrapper.vm.loadResourcesTask.last
-        wrapper.vm.selectedSpaces = spaces
-        wrapper.vm.toggleSelectAllSpaces()
-        expect(wrapper.vm.selectedSpaces.length).toBe(0)
+        wrapper.vm.selectSpaces(spaces)
+        expect(wrapper.vm.selectedSpaces.length).toBe(spaces.length)
       })
     })
     describe('toggleSelectSpace method', () => {
@@ -113,7 +103,7 @@ describe('Spaces view', () => {
       const spaces = [{ name: 'Some Space' }, { name: 'Some other Space' }]
       const { wrapper } = getWrapper({ spaces })
       await wrapper.vm.loadResourcesTask.last
-      wrapper.vm.toggleSelectAllSpaces()
+      wrapper.vm.selectSpaces(spaces)
       await wrapper.vm.$nextTick()
       expect(wrapper.find(selectors.batchActionsStub).exists()).toBeTruthy()
     })
diff --git a/packages/web-app-admin-settings/tests/unit/views/Users.spec.ts b/packages/web-app-admin-settings/tests/unit/views/Users.spec.ts
index 5996042a681..be2e28a233a 100644
--- a/packages/web-app-admin-settings/tests/unit/views/Users.spec.ts
+++ b/packages/web-app-admin-settings/tests/unit/views/Users.spec.ts
@@ -316,25 +316,6 @@ describe('Users view', () => {
     })
   })
 
-  describe('computed method "allUsersSelected"', () => {
-    it('should be true if every user is selected', async () => {
-      const { wrapper } = getMountedWrapper()
-      wrapper.vm.selectedUsers = [{ id: '1' }]
-      await wrapper.vm.loadResourcesTask.last
-      expect(wrapper.vm.allUsersSelected).toBeTruthy()
-    })
-    it('should be false if not every user is selected', async () => {
-      const clientService = getClientService()
-      clientService.graphAuthenticated.users.listUsers.mockImplementation(() =>
-        mockAxiosResolve({ value: [{ id: '1' }, { id: '2' }] })
-      )
-      const { wrapper } = getMountedWrapper({ clientService })
-      wrapper.vm.selectedUsers = [{ id: '1' }]
-      await wrapper.vm.loadResourcesTask.last
-      expect(wrapper.vm.allUsersSelected).toBeFalsy()
-    })
-  })
-
   describe('batch actions', () => {
     it('do not display when no user selected', async () => {
       const { wrapper } = getMountedWrapper({ mountType: mount })
@@ -351,7 +332,7 @@ describe('Users view', () => {
     it('display when more than one users selected', async () => {
       const { wrapper } = getMountedWrapper({ mountType: mount })
       await wrapper.vm.loadResourcesTask.last
-      wrapper.vm.toggleSelectAllUsers()
+      wrapper.vm.selectUsers([mock<User>(), mock<User>()])
       await wrapper.vm.$nextTick()
       expect(wrapper.find('batch-actions-stub').exists()).toBeTruthy()
     })
diff --git a/packages/web-app-files/src/components/Search/List.vue b/packages/web-app-files/src/components/Search/List.vue
index c31c0ba814c..973f82ebc66 100644
--- a/packages/web-app-files/src/components/Search/List.vue
+++ b/packages/web-app-files/src/components/Search/List.vue
@@ -79,7 +79,7 @@ import { mapMutations, mapGetters, mapActions } from 'vuex'
 import AppBar from '../AppBar/AppBar.vue'
 import { defineComponent, nextTick } from 'vue'
 import ListInfo from '../FilesList/ListInfo.vue'
-import Pagination from '../FilesList/Pagination.vue'
+import Pagination from 'web-pkg/src/components/Pagination.vue'
 import { useFileActions } from '../../composables/actions/files/useFileActions'
 import { searchLimit } from '../../search/sdk/list'
 import { Resource } from 'web-client'
diff --git a/packages/web-app-files/src/views/Favorites.vue b/packages/web-app-files/src/views/Favorites.vue
index 9c36c6681d3..c73225c0ae1 100644
--- a/packages/web-app-files/src/views/Favorites.vue
+++ b/packages/web-app-files/src/views/Favorites.vue
@@ -78,7 +78,7 @@ import QuickActions from '../components/FilesList/QuickActions.vue'
 import AppLoadingSpinner from 'web-pkg/src/components/AppLoadingSpinner.vue'
 import NoContentMessage from 'web-pkg/src/components/NoContentMessage.vue'
 import ListInfo from '../components/FilesList/ListInfo.vue'
-import Pagination from '../components/FilesList/Pagination.vue'
+import Pagination from 'web-pkg/src/components/Pagination.vue'
 import ContextActions from '../components/FilesList/ContextActions.vue'
 import { useResourcesViewDefaults, ViewModeConstants } from '../composables'
 import { computed, defineComponent } from 'vue'
diff --git a/packages/web-app-files/src/views/shares/SharedViaLink.vue b/packages/web-app-files/src/views/shares/SharedViaLink.vue
index 027e445f794..83d9d843ea1 100644
--- a/packages/web-app-files/src/views/shares/SharedViaLink.vue
+++ b/packages/web-app-files/src/views/shares/SharedViaLink.vue
@@ -71,11 +71,11 @@ import AppLoadingSpinner from 'web-pkg/src/components/AppLoadingSpinner.vue'
 import NoContentMessage from 'web-pkg/src/components/NoContentMessage.vue'
 import AppBar from '../../components/AppBar/AppBar.vue'
 import ListInfo from '../../components/FilesList/ListInfo.vue'
-import Pagination from '../../components/FilesList/Pagination.vue'
 import ContextActions from '../../components/FilesList/ContextActions.vue'
 import SideBar from '../../components/SideBar/SideBar.vue'
 import FilesViewWrapper from '../../components/FilesViewWrapper.vue'
 import ResourceTable from '../../components/FilesList/ResourceTable.vue'
+import Pagination from 'web-pkg/src/components/Pagination.vue'
 
 import { useResourcesViewDefaults } from '../../composables'
 import { defineComponent } from 'vue'
diff --git a/packages/web-app-files/src/views/shares/SharedWithOthers.vue b/packages/web-app-files/src/views/shares/SharedWithOthers.vue
index 804d33ab602..14ed1a249b0 100644
--- a/packages/web-app-files/src/views/shares/SharedWithOthers.vue
+++ b/packages/web-app-files/src/views/shares/SharedWithOthers.vue
@@ -70,7 +70,7 @@ import AppLoadingSpinner from 'web-pkg/src/components/AppLoadingSpinner.vue'
 import NoContentMessage from 'web-pkg/src/components/NoContentMessage.vue'
 import AppBar from '../../components/AppBar/AppBar.vue'
 import ListInfo from '../../components/FilesList/ListInfo.vue'
-import Pagination from '../../components/FilesList/Pagination.vue'
+import Pagination from 'web-pkg/src/components/Pagination.vue'
 import ContextActions from '../../components/FilesList/ContextActions.vue'
 import SideBar from '../../components/SideBar/SideBar.vue'
 import FilesViewWrapper from '../../components/FilesViewWrapper.vue'
diff --git a/packages/web-app-files/src/views/spaces/GenericSpace.vue b/packages/web-app-files/src/views/spaces/GenericSpace.vue
index 9b21164cac5..5f5c1322dec 100644
--- a/packages/web-app-files/src/views/spaces/GenericSpace.vue
+++ b/packages/web-app-files/src/views/spaces/GenericSpace.vue
@@ -153,7 +153,6 @@ import FilesViewWrapper from '../../components/FilesViewWrapper.vue'
 import KeyboardActions from '../../components/FilesList/KeyboardActions.vue'
 import ListInfo from '../../components/FilesList/ListInfo.vue'
 import NotFoundMessage from '../../components/FilesList/NotFoundMessage.vue'
-import Pagination from '../../components/FilesList/Pagination.vue'
 import QuickActions from '../../components/FilesList/QuickActions.vue'
 import ResourceTable from '../../components/FilesList/ResourceTable.vue'
 import ResourceTiles from '../../components/FilesList/ResourceTiles.vue'
@@ -161,6 +160,7 @@ import SideBar from '../../components/SideBar/SideBar.vue'
 import SpaceHeader from '../../components/Spaces/SpaceHeader.vue'
 import AppLoadingSpinner from 'web-pkg/src/components/AppLoadingSpinner.vue'
 import NoContentMessage from 'web-pkg/src/components/NoContentMessage.vue'
+import Pagination from 'web-pkg/src/components/Pagination.vue'
 import { useRoute } from 'web-pkg/src/composables'
 import { useDocumentTitle } from 'web-pkg/src/composables/appDefaults/useDocumentTitle'
 import { ImageType } from 'web-pkg/src/constants'
diff --git a/packages/web-app-files/src/views/spaces/GenericTrash.vue b/packages/web-app-files/src/views/spaces/GenericTrash.vue
index 10d6fdaaef4..b9dbb6a2c57 100644
--- a/packages/web-app-files/src/views/spaces/GenericTrash.vue
+++ b/packages/web-app-files/src/views/spaces/GenericTrash.vue
@@ -67,11 +67,11 @@ import AppBar from '../../components/AppBar/AppBar.vue'
 import ContextActions from '../../components/FilesList/ContextActions.vue'
 import FilesViewWrapper from '../../components/FilesViewWrapper.vue'
 import ListInfo from '../../components/FilesList/ListInfo.vue'
-import Pagination from '../../components/FilesList/Pagination.vue'
 import ResourceTable from '../../components/FilesList/ResourceTable.vue'
 import SideBar from '../../components/SideBar/SideBar.vue'
 import AppLoadingSpinner from 'web-pkg/src/components/AppLoadingSpinner.vue'
 import NoContentMessage from 'web-pkg/src/components/NoContentMessage.vue'
+import Pagination from 'web-pkg/src/components/Pagination.vue'
 
 import { eventBus } from 'web-pkg/src/services/eventBus'
 import { useResourcesViewDefaults } from '../../composables'
diff --git a/packages/web-pkg/src/components/ItemFilter.vue b/packages/web-pkg/src/components/ItemFilter.vue
index c045bce7af2..86302d82af8 100644
--- a/packages/web-pkg/src/components/ItemFilter.vue
+++ b/packages/web-pkg/src/components/ItemFilter.vue
@@ -115,7 +115,7 @@ export default defineComponent({
     const queryParam = `q_${props.filterName}`
     const currentRouteQuery = useRouteQuery(queryParam)
     const setRouteQuery = () => {
-      router.push({
+      return router.push({
         query: {
           ...omit(unref(currentRoute).query, [queryParam]),
           ...(!!unref(selectedItems).length && {
@@ -136,7 +136,7 @@ export default defineComponent({
     const isSelectionAllowed = (item) => {
       return props.allowMultiple || !unref(selectedItems).length || isItemSelected(item)
     }
-    const toggleItemSelection = (item) => {
+    const toggleItemSelection = async (item) => {
       if (!isSelectionAllowed(item)) {
         return
       }
@@ -145,8 +145,8 @@ export default defineComponent({
       } else {
         selectedItems.value.push(item)
       }
+      await setRouteQuery()
       emit('selectionChange', unref(selectedItems))
-      setRouteQuery()
     }
 
     const sortItems = (items) => {
@@ -247,4 +247,3 @@ export default defineComponent({
   }
 }
 </style>
-
diff --git a/packages/web-app-files/src/components/FilesList/Pagination.vue b/packages/web-pkg/src/components/Pagination.vue
similarity index 100%
rename from packages/web-app-files/src/components/FilesList/Pagination.vue
rename to packages/web-pkg/src/components/Pagination.vue
diff --git a/packages/web-app-files/tests/unit/components/FilesList/Pagination.spec.ts b/packages/web-pkg/tests/unit/components/Pagination.spec.ts
similarity index 96%
rename from packages/web-app-files/tests/unit/components/FilesList/Pagination.spec.ts
rename to packages/web-pkg/tests/unit/components/Pagination.spec.ts
index fd2d6b640c8..259d5604508 100644
--- a/packages/web-app-files/tests/unit/components/FilesList/Pagination.spec.ts
+++ b/packages/web-pkg/tests/unit/components/Pagination.spec.ts
@@ -1,6 +1,5 @@
 import { mock } from 'jest-mock-extended'
 import _ from 'lodash'
-import Pagination from 'web-app-files/src/components/FilesList/Pagination.vue'
 import {
   defaultPlugins,
   mount,
@@ -9,6 +8,7 @@ import {
   defaultComponentMocks,
   RouteLocation
 } from 'web-test-helpers'
+import Pagination from 'web-pkg/src/components/Pagination.vue'
 
 const filesPersonalRoute = { name: 'files-personal', path: '/files/home' }