diff --git a/resources/vue/components/courseware/plugin-manager.js b/resources/vue/components/courseware/plugin-manager.js
index 26ee566f8d718f7169c83e9966cba5717e9c4ae1..5326fd992617128bfed8ba55b09121fd5028aa48 100644
--- a/resources/vue/components/courseware/plugin-manager.js
+++ b/resources/vue/components/courseware/plugin-manager.js
@@ -1,3 +1,7 @@
+import { useBlockCategoryManager } from '../../composables/courseware/useBlockCategoryManager.js';
+
+const { addCategory } = useBlockCategoryManager();
+
 class PluginManager {
     constructor() {
         this.blocks = [];
@@ -7,6 +11,11 @@ class PluginManager {
     addBlock(name, block) {
         this.blocks[name] = block;
     }
+
+    addCategory(title, type) {
+        addCategory(title, type);
+    }
+
     addContainer(name, container) {
         this.containers[name] = container;
     }
diff --git a/resources/vue/components/courseware/toolbar/CoursewareToolbarBlocks.vue b/resources/vue/components/courseware/toolbar/CoursewareToolbarBlocks.vue
index 922b8c6ada3d9de5cfd2112951cf10cd5071e7ea..c39f43eceeb2ca884410514a613dd8c421fbe08a 100644
--- a/resources/vue/components/courseware/toolbar/CoursewareToolbarBlocks.vue
+++ b/resources/vue/components/courseware/toolbar/CoursewareToolbarBlocks.vue
@@ -8,7 +8,7 @@
                         type="text"
                         v-model="searchInput"
                         @click.stop
-                        :label="$gettext('Geben Sie einen Suchbegriff mit mindestens 3 Zeichen ein.')"
+                        :aria-label="$gettext('Geben Sie einen Suchbegriff mit mindestens 3 Zeichen ein.')"
                     />
                     <span class="input-group-append" @click.stop>
                         <button
@@ -35,17 +35,26 @@
             </form>
 
             <div id="filterpanel" class="filterpanel">
-                <span class="sr-only">{{ $gettext('Kategorien-Filter') }}</span>
-                <button
-                    v-for="category in blockCategories"
-                    :key="category.type"
-                    class="button"
-                    :class="{ 'active': category.type === currentFilterCategory }"
-                    :aria-pressed="category.type === currentFilterCategory ? 'true' : 'false'"
-                    @click="selectCategory(category.type)"
-                >
-                    {{ category.title }}
-                </button>
+                <form class="default">
+                  <span class="sr-only">{{ $gettext('Kategorien-Filter') }}</span>
+                  <studip-select
+                      :clearable="true"
+                      label="title"
+                      :options="blockCategories"
+                      :placeholder="$gettext('Blockkategorien')"
+                      :reduce="(category) => category.type"
+                      v-model="currentFilterCategory"
+                      >
+                      <template #open-indicator="selectAttributes">
+                          <span v-bind="selectAttributes"><studip-icon shape="arr_1down" :size="10" /></span>
+                      </template>
+                      <template #no-options>
+                          {{ $gettext('Es steht keine Auswahl zur Verfügung.') }}
+                      </template>
+                      <template #selected-option="{ title }"><span>{{ title }}</span></template>
+                      <template #option="{ title }"><span>{{ title }}</span></template>
+                  </studip-select>
+                </form>
             </div>
         </div>
         <div class="cw-toolbar-tool-content" :style="toolContentStyle">
@@ -91,6 +100,7 @@ import CoursewareBlockadderItem from './CoursewareBlockadderItem.vue';
 import CoursewareCompanionBox from '../layouts/CoursewareCompanionBox.vue';
 import containerMixin from '@/vue/mixins/courseware/container.js';
 import draggable from 'vuedraggable';
+import { useBlockCategoryManager } from '../../../composables/courseware/useBlockCategoryManager.js';
 
 import { mapActions, mapGetters } from 'vuex';
 
@@ -108,6 +118,11 @@ export default {
             required: true,
         },
     },
+    setup() {
+        const { categories } = useBlockCategoryManager();
+
+        return { categories };
+    },
     data() {
         return {
             searchInput: '',
@@ -124,21 +139,12 @@ export default {
             favoriteBlockTypes: 'favoriteBlockTypes',
         }),
         blockTypes() {
-            let blockTypes = JSON.parse(JSON.stringify(this.unorderedBlockTypes));
-            blockTypes.sort((a, b) => {
-                return a.title > b.title ? 1 : b.title > a.title ? -1 : 0;
-            });
-            return blockTypes;
+            return _.sortBy(JSON.parse(JSON.stringify(this.unorderedBlockTypes)), ['title']);
         },
         blockCategories() {
             return [
                 { title: this.$gettext('Favoriten'), type: 'favorite' },
-                { title: this.$gettext('Texte'), type: 'text' },
-                { title: this.$gettext('Multimedia'), type: 'multimedia' },
-                { title: this.$gettext('Interaktion'), type: 'interaction' },
-                { title: this.$gettext('Gestaltung'), type: 'layout' },
-                { title: this.$gettext('Externe Inhalte'), type: 'external' },
-                { title: this.$gettext('Biografie'), type: 'biography' },
+                ..._.sortBy(this.categories, ['title']),
             ];
         },
         toolContentStyle() {
@@ -215,21 +221,6 @@ export default {
                 return false;
             });
         },
-        selectCategory(type) {
-            if (this.currentFilterCategory !== type) {
-                this.currentFilterCategory = type;
-            } else {
-                this.resetCategory();
-            }
-        },
-        resetCategory() {
-            this.currentFilterCategory = '';
-            if (!this.searchInput) {
-                this.filteredBlockTypes = this.blockTypes;
-            } else {
-                this.loadSearch();
-            }
-        },
         resetSearch() {
             this.filteredBlockTypes = this.blockTypes;
             this.searchInput = '';
@@ -301,9 +292,15 @@ export default {
                 }
             }
         },
-        currentFilterCategory(newValue) {
+        currentFilterCategory(newValue, oldValue) {
             if (newValue) {
                 this.loadSearch();
+            } else {
+                if (!this.searchInput) {
+                    this.filteredBlockTypes = this.blockTypes;
+                } else {
+                    this.loadSearch();
+                }
             }
         },
     },
diff --git a/resources/vue/composables/courseware/useBlockCategoryManager.js b/resources/vue/composables/courseware/useBlockCategoryManager.js
new file mode 100644
index 0000000000000000000000000000000000000000..09cbb4ccd88e75c3e99be331c899ffcb33b89e12
--- /dev/null
+++ b/resources/vue/composables/courseware/useBlockCategoryManager.js
@@ -0,0 +1,19 @@
+import { ref } from 'vue';
+import { $gettext } from '../../../assets/javascripts/lib/gettext';
+
+const categories = ref([
+    { title: $gettext('Texte'), type: 'text' },
+    { title: $gettext('Multimedia'), type: 'multimedia' },
+    { title: $gettext('Interaktion'), type: 'interaction' },
+    { title: $gettext('Gestaltung'), type: 'layout' },
+    { title: $gettext('Externe Inhalte'), type: 'external' },
+    { title: $gettext('Biografie'), type: 'biography' },
+]);
+
+export const useBlockCategoryManager = () => {
+    const addCategory = (title, type) => {
+        categories.value = [...categories.value.filter((category) => category.type !== type), { title, type }];
+    };
+
+    return { categories, addCategory };
+};