diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/cluster_filter.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/cluster_filter.vue
index c388e974cb56e60b0cd3b65104f649de91f9b260..4b75d9a0c9b4b4c2e6797cc59e39804d8bba7fe0 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/shared/filters/cluster_filter.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/filters/cluster_filter.vue
@@ -1,20 +1,16 @@
 <script>
-import { GlDropdown } from '@gitlab/ui';
-import { xor } from 'lodash';
+import { GlCollapsibleListbox } from '@gitlab/ui';
 import { s__ } from '~/locale';
 import getClusterAgentsQuery from 'ee/security_dashboard/graphql/queries/cluster_agents.query.graphql';
 import { createAlert } from '~/alert';
-import FilterItem from './filter_item.vue';
 import QuerystringSync from './querystring_sync.vue';
-import DropdownButtonText from './dropdown_button_text.vue';
 import { ALL_ID } from './constants';
+import { getSelectedOptionsText } from './utils';
 
 export default {
   components: {
-    FilterItem,
-    GlDropdown,
+    GlCollapsibleListbox,
     QuerystringSync,
-    DropdownButtonText,
   },
   apollo: {
     clusterAgents: {
@@ -26,8 +22,8 @@ export default {
       },
       update: (data) =>
         data.project?.clusterAgents?.nodes.map((c) => ({
-          id: c.name,
-          name: c.name,
+          value: c.name,
+          text: c.name,
           gid: c.id,
         })) || [],
       error() {
@@ -41,30 +37,43 @@ export default {
     selected: [],
   }),
   computed: {
-    selectedItemNames() {
-      const options = this.clusterAgents?.filter(({ id }) => this.selected.includes(id));
-      // Return the text for selected items, or all items if nothing is selected.
-      return options.length ? options.map(({ name }) => name) : [this.$options.i18n.allItemsText];
+    toggleText() {
+      const options = this.clusterAgents?.filter(({ value }) => this.selected.includes(value));
+      return getSelectedOptionsText(options, this.selected, this.$options.i18n.allItemsText);
     },
     isLoading() {
       return this.$apollo.queries.clusterAgents.loading;
     },
+    items() {
+      return [
+        {
+          text: this.$options.i18n.allItemsText,
+          value: ALL_ID,
+        },
+        ...this.clusterAgents,
+      ];
+    },
+    selectedItems() {
+      return this.selected.length ? this.selected : [ALL_ID];
+    },
   },
   watch: {
     selected() {
       const gids = this.clusterAgents
-        .filter(({ id }) => this.selected.includes(id))
+        .filter(({ value }) => this.selected.includes(value))
         .map(({ gid }) => gid);
 
       this.$emit('filter-changed', { clusterAgentId: gids });
     },
   },
   methods: {
-    deselectAll() {
-      this.selected = [];
-    },
-    toggleSelected(id) {
-      this.selected = xor(this.selected, [id]);
+    handleSelect(selected) {
+      if (selected?.at(-1) === ALL_ID) {
+        this.selected = [];
+        return;
+      }
+
+      this.selected = selected.filter((value) => value !== ALL_ID);
     },
   },
   i18n: {
@@ -80,31 +89,15 @@ export default {
   <div>
     <querystring-sync v-model="selected" querystring-key="cluster" />
     <label class="gl-mb-2">{{ $options.i18n.label }}</label>
-    <gl-dropdown
+    <gl-collapsible-listbox
+      :selected="selectedItems"
+      :items="items"
+      :toggle-text="toggleText"
       :header-text="$options.i18n.label"
       :loading="isLoading"
+      multiple
       block
-      toggle-class="gl-mb-0"
-    >
-      <template #button-text>
-        <dropdown-button-text :items="selectedItemNames" :name="$options.i18n.label" />
-      </template>
-
-      <filter-item
-        :is-checked="!selected.length"
-        :text="$options.i18n.allItemsText"
-        :data-testid="$options.ALL_ID"
-        @click="deselectAll"
-      />
-
-      <filter-item
-        v-for="{ id } in clusterAgents"
-        :key="id"
-        :data-testid="id"
-        :is-checked="selected.includes(id)"
-        :text="id"
-        @click="toggleSelected(id)"
-      />
-    </gl-dropdown>
+      @select="handleSelect"
+    />
   </div>
 </template>
diff --git a/ee/spec/frontend/security_dashboard/components/mock_data.js b/ee/spec/frontend/security_dashboard/components/mock_data.js
index 350c5ba68e9168d8f0cb56eb3ff6d0fddba4a039..3fe81119df628de0bf4e0b65d681afc5ffb20202 100644
--- a/ee/spec/frontend/security_dashboard/components/mock_data.js
+++ b/ee/spec/frontend/security_dashboard/components/mock_data.js
@@ -54,6 +54,11 @@ export const projectClusters = {
             name: 'primary-agent',
             __typename: 'ClusterAgentConnection',
           },
+          {
+            id: 'gid://gitlab/Clusters::Agent/007',
+            name: 'james-bond-agent',
+            __typename: 'ClusterAgentConnection',
+          },
         ],
         __typename: 'ClusterAgentConnection',
       },
diff --git a/ee/spec/frontend/security_dashboard/components/shared/filters/cluster_filter_spec.js b/ee/spec/frontend/security_dashboard/components/shared/filters/cluster_filter_spec.js
index e1095f617ae1b408a3f36ee299eaee3a72dc6e77..3a21dc4f860c701b7d2e19495fe133acecacceee 100644
--- a/ee/spec/frontend/security_dashboard/components/shared/filters/cluster_filter_spec.js
+++ b/ee/spec/frontend/security_dashboard/components/shared/filters/cluster_filter_spec.js
@@ -1,10 +1,8 @@
-import { GlDropdown } from '@gitlab/ui';
+import { GlCollapsibleListbox } from '@gitlab/ui';
 import Vue, { nextTick } from 'vue';
 import VueApollo from 'vue-apollo';
 import ClusterFilter from 'ee/security_dashboard/components/shared/filters/cluster_filter.vue';
 import QuerystringSync from 'ee/security_dashboard/components/shared/filters/querystring_sync.vue';
-import DropdownButtonText from 'ee/security_dashboard/components/shared/filters/dropdown_button_text.vue';
-import FilterItem from 'ee/security_dashboard/components/shared/filters/filter_item.vue';
 import { mountExtended } from 'helpers/vue_test_utils_helper';
 import { ALL_ID } from 'ee/security_dashboard/components/shared/filters/constants';
 import waitForPromises from 'helpers/wait_for_promises';
@@ -20,6 +18,7 @@ describe('ClusterFilter component', () => {
   let wrapper;
   const defaultQueryResolver = jest.fn().mockResolvedValue(projectClusters);
   const mockClusters = projectClusters.data.project.clusterAgents.nodes;
+  const firstMockClusterName = mockClusters[0].name;
 
   const createWrapper = (queryResolver = defaultQueryResolver) => {
     wrapper = mountExtended(ClusterFilter, {
@@ -30,20 +29,15 @@ describe('ClusterFilter component', () => {
   };
 
   const findQuerystringSync = () => wrapper.findComponent(QuerystringSync);
-  const findDropdownItems = () => wrapper.findAllComponents(FilterItem);
-  const findDropdownItem = (name) => wrapper.findByTestId(name);
+  const findListbox = () => wrapper.findComponent(GlCollapsibleListbox);
+  const findListboxItem = (name) => wrapper.findByTestId(`listbox-item-${name}`);
 
-  const clickDropdownItem = async (name) => {
-    findDropdownItem(name).trigger('click');
-    await nextTick();
+  const clickListboxItem = (name) => {
+    return findListboxItem(name).trigger('click');
   };
 
   const expectSelectedItems = (ids) => {
-    const checkedItems = findDropdownItems()
-      .wrappers.filter((item) => item.props('isChecked'))
-      .map((item) => item.attributes('data-testid'));
-
-    expect(checkedItems).toEqual(ids);
+    expect(findListbox().props('selected')).toEqual(ids);
   };
 
   describe('basic structure', () => {
@@ -63,7 +57,7 @@ describe('ClusterFilter component', () => {
       it.each`
         emitted                   | expected
         ${[]}                     | ${[ALL_ID]}
-        ${[mockClusters[0].name]} | ${[mockClusters[0].name]}
+        ${[firstMockClusterName]} | ${[firstMockClusterName]}
       `('restores selected items - $emitted', async ({ emitted, expected }) => {
         findQuerystringSync().vm.$emit('input', emitted);
         await nextTick();
@@ -77,29 +71,37 @@ describe('ClusterFilter component', () => {
         expect(wrapper.find('label').text()).toBe(ClusterFilter.i18n.label);
       });
 
-      it('shows the dropdown with correct header text', () => {
-        expect(wrapper.findComponent(GlDropdown).props('headerText')).toBe(
-          ClusterFilter.i18n.label,
-        );
+      it('shows the listbox with correct header text', () => {
+        expect(findListbox().props('headerText')).toBe(ClusterFilter.i18n.label);
       });
 
-      it('shows the DropdownButtonText component with the correct props', () => {
-        expect(wrapper.findComponent(DropdownButtonText).props()).toMatchObject({
-          items: [ClusterFilter.i18n.allItemsText],
-          name: ClusterFilter.i18n.label,
-        });
+      it('passes the placeholder toggle text when no items are selected', () => {
+        expect(findListbox().props('toggleText')).toBe(ClusterFilter.i18n.allItemsText);
+      });
+
+      it(`passes '${firstMockClusterName}' when only ${firstMockClusterName} is selected`, async () => {
+        await clickListboxItem(firstMockClusterName);
+
+        expect(findListbox().props('toggleText')).toBe(firstMockClusterName);
+      });
+
+      it(`passes '${firstMockClusterName} +1 more' when ${firstMockClusterName} and another image is selected`, async () => {
+        await clickListboxItem(firstMockClusterName);
+        await clickListboxItem(mockClusters[1].name);
+
+        expect(findListbox().props('toggleText')).toBe(`${firstMockClusterName} +1 more`);
       });
     });
 
     describe('filter-changed event', () => {
       it('emits filter-changed event when selected item is changed', async () => {
         const ids = [];
-        await clickDropdownItem(ALL_ID);
+        await clickListboxItem(ALL_ID);
 
         expect(wrapper.emitted('filter-changed')[0][0].clusterAgentId).toEqual([]);
 
         for await (const { id, name } of mockClusters) {
-          await clickDropdownItem(name);
+          await clickListboxItem(name);
           ids.push(id);
 
           expect(wrapper.emitted('filter-changed')[ids.length][0].clusterAgentId).toEqual(ids);
@@ -107,13 +109,13 @@ describe('ClusterFilter component', () => {
       });
     });
 
-    describe('dropdown items', () => {
+    describe('listbox items', () => {
       it('populates all dropdown items with correct text', () => {
-        expect(findDropdownItems()).toHaveLength(mockClusters.length + 1);
-        expect(findDropdownItem(ALL_ID).text()).toBe(ClusterFilter.i18n.allItemsText);
+        expect(findListbox().props('items')).toHaveLength(mockClusters.length + 1);
+        expect(findListboxItem(ALL_ID).text()).toBe(ClusterFilter.i18n.allItemsText);
 
         mockClusters.forEach(({ name }) => {
-          expect(findDropdownItem(name).text()).toBe(name);
+          expect(findListboxItem(name).text()).toBe(name);
         });
       });
 
@@ -121,7 +123,7 @@ describe('ClusterFilter component', () => {
         const names = [];
 
         for await (const { name } of mockClusters) {
-          await clickDropdownItem(name);
+          await clickListboxItem(name);
           names.push(name);
 
           expectSelectedItems(names);
@@ -130,11 +132,11 @@ describe('ClusterFilter component', () => {
 
       it('toggles the item selection when clicked on', async () => {
         for await (const { name } of mockClusters) {
-          await clickDropdownItem(name);
+          await clickListboxItem(name);
 
           expectSelectedItems([name]);
 
-          await clickDropdownItem(name);
+          await clickListboxItem(name);
 
           expectSelectedItems([ALL_ID]);
         }
@@ -145,17 +147,17 @@ describe('ClusterFilter component', () => {
       });
 
       it('selects ALL item and deselects everything else when it is clicked', async () => {
-        await clickDropdownItem(ALL_ID);
-        await clickDropdownItem(ALL_ID); // Click again to verify that it doesn't toggle.
+        await clickListboxItem(ALL_ID);
+        await clickListboxItem(ALL_ID); // Click again to verify that it doesn't toggle.
 
         expectSelectedItems([ALL_ID]);
       });
 
       it('deselects the ALL item when another item is clicked', async () => {
-        await clickDropdownItem(ALL_ID);
-        await clickDropdownItem(mockClusters[0].name);
+        await clickListboxItem(ALL_ID);
+        await clickListboxItem(firstMockClusterName);
 
-        expectSelectedItems([mockClusters[0].name]);
+        expectSelectedItems([firstMockClusterName]);
       });
     });
   });