diff --git a/app/controllers/search/courses.php b/app/controllers/search/courses.php
index 50a348066fa9dad1f5333c435729b2b6fe4d3cc8..9e0b45d6e31adfa3df193efccc5487c99501a63d 100644
--- a/app/controllers/search/courses.php
+++ b/app/controllers/search/courses.php
@@ -28,6 +28,10 @@ class Search_CoursesController extends AuthenticatedController
         PageLayout::setHelpKeyword('Basis.VeranstaltungenAbonnieren');
 
         $this->type = Request::option('type', 'semtree');
+        $this->show_as = Request::option('show_as', 'list');
+        if (!in_array($this->show_as, ['list', 'table'])) {
+            $this->show_as = 'list';
+        }
         $this->semester = Request::option('semester', Semester::findCurrent()->id);
         $this->semClass = Request::int('semclass', 0);
         $this->search = Request::get('search', '');
@@ -107,5 +111,16 @@ class Search_CoursesController extends AuthenticatedController
 
         $sidebar->addWidget(new VueWidget('search-widget'));
         $sidebar->addWidget(new VueWidget('export-widget'));
+
+        $views = new ViewsWidget();
+        $views->addLink(
+            _('Als Liste'),
+            $this->url_for('search/courses', array_merge($params, ['show_as' => 'list']))
+        )->setActive($this->show_as === 'list');
+        $views->addLink(
+            _('Als Tabelle'),
+            $this->url_for('search/courses', array_merge($params, ['show_as' => 'table']))
+        )->setActive($this->show_as === 'table');
+        $sidebar->addWidget($views);
     }
 }
diff --git a/app/views/search/courses/index.php b/app/views/search/courses/index.php
index c6f490506018972d0765c56676e34fb9b73d6835..500c31e7f69d808dfe18fdaeceab04a16ba03744 100644
--- a/app/views/search/courses/index.php
+++ b/app/views/search/courses/index.php
@@ -1,11 +1,15 @@
 <?php
 /**
  * @var String $startId
- * @var String $nodeClass
+ * @var String $show_as
+ * @var String $treeTitle
+ * @var String $breadcrumIcon
+ * @var String $semester
+ * @var String $semClass
  */
 ?>
 <div data-studip-tree>
-    <studip-tree start-id="<?= htmlReady($startId) ?>" view-type="list" :visible-children-only="true"
+    <studip-tree start-id="<?= htmlReady($startId) ?>" view-type="<?= htmlReady($show_as) ?>" :visible-children-only="true"
                  title="<?= htmlReady($treeTitle) ?>" breadcrumb-icon="<?= htmlReady($breadcrumbIcon) ?>"
                  :with-search="true" :with-export="true" :with-courses="true" semester="<?= htmlReady($semester) ?>"
                  :sem-class="<?= htmlReady($semClass) ?>" :with-export="true"></studip-tree>
diff --git a/lib/classes/JsonApi/Routes/Tree/CourseInfoOfTreeNode.php b/lib/classes/JsonApi/Routes/Tree/CourseInfoOfTreeNode.php
index 283593150cf5c0c4ec8d3fb5cc0ae2555b9ff2d4..e684c40301b2e26d4a3c9e109129229de257753f 100644
--- a/lib/classes/JsonApi/Routes/Tree/CourseInfoOfTreeNode.php
+++ b/lib/classes/JsonApi/Routes/Tree/CourseInfoOfTreeNode.php
@@ -32,8 +32,7 @@ class CourseinfoOfTreeNode extends NonJsonApiController
         $filters = $this->getContextFilters($request);
 
         $info = [
-            'courses' => (int) $node->countCourses($filters['semester'], $filters['semclass']),
-            'allCourses' => (int) $node->countCourses($filters['semester'], $filters['semclass'], true)
+            'courses' => (int) $node->countCourses($filters['semester'], $filters['semclass'], true)
         ];
 
         $response->getBody()->write(json_encode($info));
diff --git a/lib/models/StudipStudyArea.class.php b/lib/models/StudipStudyArea.class.php
index 444ca21291237d152b8aa2e2824c2f96675732c5..2d13b186eff39112472337fe562899f9a2649c9d 100644
--- a/lib/models/StudipStudyArea.class.php
+++ b/lib/models/StudipStudyArea.class.php
@@ -494,7 +494,7 @@ class StudipStudyArea extends SimpleORMap implements StudipTreeNode
                           OR sc.`semester_id` IS NULL
                         )";
             $parameters = [
-                'ids' => $with_children ? $this->getDescendantIds() : [$this->id],
+                'ids' => $with_children ? array_merge([$this->id], $this->getDescendantIds()) : [$this->id],
                 'semester' => $semester_id
             ];
         } else {
@@ -502,7 +502,7 @@ class StudipStudyArea extends SimpleORMap implements StudipTreeNode
                       FROM `seminar_sem_tree` t
                       JOIN `seminare` s ON (s.`Seminar_id` = t.`seminar_id`)
                       WHERE `sem_tree_id` IN (:ids)";
-            $parameters = ['ids' => $with_children ? $this->getDescendantIds() : [$this->id]];
+            $parameters = ['ids' => $with_children ? array_merge([$this->id], $this->getDescendantIds()) : [$this->id]];
         }
 
         if (!$GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)) {
diff --git a/resources/assets/stylesheets/scss/loading-skeleton.scss b/resources/assets/stylesheets/scss/loading-skeleton.scss
new file mode 100644
index 0000000000000000000000000000000000000000..480255fe502110970ee3daf54dec1768addf3240
--- /dev/null
+++ b/resources/assets/stylesheets/scss/loading-skeleton.scss
@@ -0,0 +1,5 @@
+.studip-loading-skeleton {
+    background-color: var(--light-gray-color-20);
+    height: 1em;
+    width: 100%;
+}
diff --git a/resources/assets/stylesheets/scss/tree.scss b/resources/assets/stylesheets/scss/tree.scss
index dbad68b1bc507c14dacc893b93662e8631eb6e84..1d700f92eb5d1b29b85151f055abd167e56bae47 100644
--- a/resources/assets/stylesheets/scss/tree.scss
+++ b/resources/assets/stylesheets/scss/tree.scss
@@ -271,8 +271,8 @@ $tree-outline: 1px solid var(--light-gray-color-40);
                 background: var(--dark-gray-color-5);
                 border: solid thin var(--light-gray-color-40);
                 display: flex;
-                height: 130px;
-                padding: 10px;
+                min-height: 130px;
+                padding: 5px 10px;
 
                 /* Handle for drag&drop */
                 .drag-handle {
@@ -284,11 +284,17 @@ $tree-outline: 1px solid var(--light-gray-color-40);
                     flex-direction: column;
                     padding: 10px;
                     text-align: left;
+                    width: 100%;
 
                     .studip-tree-child-title {
                         font-size: 1.1em;
                         font-weight: bold;
                     }
+
+                    .studip-tree-child-description {
+                        color: var(--black);
+                        font-size: 0.9em;
+                    }
                 }
 
                 &:hover {
diff --git a/resources/assets/stylesheets/studip.scss b/resources/assets/stylesheets/studip.scss
index e45cdb3f63f5fe2480726b70fda004897528efea..b0e768ea172bf86327d5c2a7361450a94a4b1171 100644
--- a/resources/assets/stylesheets/studip.scss
+++ b/resources/assets/stylesheets/studip.scss
@@ -57,6 +57,7 @@
 @import "scss/globalsearch";
 @import "scss/links";
 @import "scss/lists";
+@import "scss/loading-skeleton.scss";
 @import "scss/messages";
 @import "scss/my_courses";
 @import "scss/mvv";
diff --git a/resources/vue/components/StudipLoadingSkeleton.vue b/resources/vue/components/StudipLoadingSkeleton.vue
new file mode 100644
index 0000000000000000000000000000000000000000..90b973397032cfb35556dea67c5ed76377d73c76
--- /dev/null
+++ b/resources/vue/components/StudipLoadingSkeleton.vue
@@ -0,0 +1,9 @@
+<template>
+    <div class="studip-loading-skeleton"></div>
+</template>
+
+<script>
+export default {
+    name: 'StudipLoadingSkeleton'
+}
+</script>
diff --git a/resources/vue/components/tree/StudipTreeList.vue b/resources/vue/components/tree/StudipTreeList.vue
index b607e02197a1bff868fe4a3ce73a0866055b7e56..4ba08bcbb81200e3751530c7c3c32e8fda65d3e9 100644
--- a/resources/vue/components/tree/StudipTreeList.vue
+++ b/resources/vue/components/tree/StudipTreeList.vue
@@ -62,8 +62,8 @@
             </span>
             <span v-if="withCourses && subLevelsCourses > 0 && !showingAllCourses">
                 <button type="button" @click="showAllCourses(true)"
-                        :title="$gettext('Veranstaltungen auf allen Unterebenen anzeigen')">
-                    {{ $gettext('Veranstaltungen auf allen Unterebenen anzeigen') }}
+                        :title="$gettext('Veranstaltungen auf Unterebenen anzeigen')">
+                    {{ $gettext('Veranstaltungen auf Unterebenen anzeigen') }}
                 </button>
             </span>
         </section>
@@ -74,6 +74,15 @@
                 <col>
             </colgroup>
             <thead>
+                <tr v-if="totalCourseCount > limit">
+                    <td colspan="2">
+                        <studip-pagination :items-per-page="limit"
+                                           :total-items="totalCourseCount"
+                                           :current-offset="offset"
+                                           @updateOffset="updateOffset"
+                        />
+                    </td>
+                </tr>
                 <tr>
                     <th>{{ $gettext('Name') }}</th>
                     <th>{{ $gettext('Information') }}</th>
@@ -98,6 +107,17 @@
                     </td>
                 </tr>
             </tbody>
+            <tfoot v-if="totalCourseCount > limit">
+                <tr>
+                    <td colspan="2">
+                        <studip-pagination :items-per-page="limit"
+                                           :total-items="totalCourseCount"
+                                           :current-offset="offset"
+                                           @updateOffset="updateOffset"
+                        />
+                    </td>
+                </tr>
+            </tfoot>
         </table>
         <MountingPortal v-if="showExport" mountTo="#export-widget" name="sidebar-export">
             <tree-export-widget v-if="courses.length > 0"
@@ -118,13 +138,14 @@ import TreeBreadcrumb from './TreeBreadcrumb.vue';
 import TreeNodeTile from './TreeNodeTile.vue';
 import StudipProgressIndicator from '../StudipProgressIndicator.vue';
 import TreeCourseDetails from './TreeCourseDetails.vue';
-import AssignLinkWidget from "./AssignLinkWidget.vue";
+import AssignLinkWidget from './AssignLinkWidget.vue';
+import StudipPagination from '../StudipPagination.vue';
 
 export default {
     name: 'StudipTreeList',
     components: {
         draggable, StudipProgressIndicator, TreeExportWidget, TreeBreadcrumb, TreeNodeTile, TreeCourseDetails,
-        AssignLinkWidget
+        AssignLinkWidget, StudipPagination
     },
     mixins: [ TreeMixin ],
     props: {
@@ -225,8 +246,10 @@ export default {
                 });
 
             if (this.withCourses) {
-                this.getNodeCourses(node, this.semester, this.semClass, '', false)
+                this.getNodeCourses(node, this.offset, this.semester, this.semClass, '', false)
                     .then(courses => {
+                        this.totalCourseCount = courses.data.meta.page.total;
+                        this.offset = Math.ceil(courses.data.meta.page.offset / this.limit);
                         this.courses = courses.data.data;
                     });
             }
@@ -288,8 +311,10 @@ export default {
             }
         },
         showAllCourses(state) {
-            this.getNodeCourses(this.currentNode, this.semester, this.semClass, '', state)
+            this.getNodeCourses(this.currentNode, this.offset, this.semester, this.semClass, '', state)
                 .then(courses => {
+                    this.totalCourseCount = courses.data.meta.page.total;
+                    this.offset = Math.ceil(courses.data.meta.page.offset / this.limit);
                     this.courses = courses.data.data;
                     this.showingAllCourses = state;
                 });
@@ -309,8 +334,10 @@ export default {
             });
 
         if (this.withCourses) {
-            this.getNodeCourses(this.currentNode, this.semester, this.semClass)
+            this.getNodeCourses(this.currentNode, 0, this.semester, this.semClass)
                 .then(courses => {
+                    this.totalCourseCount = courses.data.meta.page.total;
+                    this.offset = 0;
                     this.courses = courses.data.data;
                 });
         }
diff --git a/resources/vue/components/tree/StudipTreeNode.vue b/resources/vue/components/tree/StudipTreeNode.vue
index 39f696ccc14e12480701eb2501a71b34cffacf4a..2b5676e24a38455201ff5b0c6a898036f231b1ba 100644
--- a/resources/vue/components/tree/StudipTreeNode.vue
+++ b/resources/vue/components/tree/StudipTreeNode.vue
@@ -175,7 +175,7 @@ export default {
             }
 
             if (ids.length > 0) {
-                this.getNodeCourses(this.node, 'all', 0, '', false, ids)
+                this.getNodeCourses(this.node, 0, 'all', 0, '', false, ids)
                     .then(response => {
                         // None of the given courses are assigned here.
                         if (response.data.data.length === 0) {
diff --git a/resources/vue/components/tree/StudipTreeTable.vue b/resources/vue/components/tree/StudipTreeTable.vue
index 585acd426046c1cda90ac862d5354bf105c36a96..03a9d7b60e9ac64c2263d4da5b609e1717ce0495 100644
--- a/resources/vue/components/tree/StudipTreeTable.vue
+++ b/resources/vue/components/tree/StudipTreeTable.vue
@@ -35,8 +35,8 @@
             </template>
             <span v-if="withCourses && subLevelsCourses > 0 && !showingAllCourses">
                 <button type="button" @click="showAllCourses(true)"
-                        :title="$gettext('Veranstaltungen auf allen Unterebenen anzeigen')">
-                    {{ $gettext('Veranstaltungen auf allen Unterebenen anzeigen') }}
+                        :title="$gettext('Veranstaltungen auf Unterebenen anzeigen')">
+                    {{ $gettext('Veranstaltungen auf Unterebenen anzeigen') }}
                 </button>
             </span>
         </section>
@@ -57,6 +57,15 @@
                 <col style="width: 40%">
             </colgroup>
             <thead>
+                <tr v-if="totalCourseCount > limit">
+                    <td colspan="4">
+                        <studip-pagination :items-per-page="limit"
+                                           :total-items="totalCourseCount"
+                                           :current-offset="offset"
+                                           @updateOffset="updateOffset"
+                        />
+                    </td>
+                </tr>
                 <tr>
                     <th></th>
                     <th>{{ $gettext('Typ') }}</th>
@@ -89,8 +98,11 @@
                         </a>
                     </td>
                     <td>
-                        <tree-node-course-info :node="child" :semester="semester"
-                                               :sem-class="semClass"></tree-node-course-info>
+                        <tree-node-course-info v-if="node.attributes.ancestors.length > 2"
+                                               :node="child"
+                                               :semester="semester"
+                                               :sem-class="semClass"
+                        ></tree-node-course-info>
                     </td>
                 </tr>
                 <tr v-for="(course) in courses" :key="course.id" class="studip-tree-child studip-tree-course">
@@ -114,6 +126,17 @@
                     </td>
                 </tr>
             </draggable>
+            <tfoot v-if="totalCourseCount > limit">
+                <tr>
+                    <td colspan="4">
+                        <studip-pagination :items-per-page="limit"
+                                           :total-items="totalCourseCount"
+                                           :current-offset="offset"
+                                           @updateOffset="updateOffset"
+                        />
+                    </td>
+                </tr>
+            </tfoot>
         </table>
         <MountingPortal v-if="showExport" mountTo="#export-widget" name="sidebar-export">
             <tree-export-widget v-if="courses.length > 0" :title="$gettext('Download des Ergebnisses')" :url="exportUrl()"
@@ -242,8 +265,10 @@ export default {
 
             if (this.withCourses) {
 
-                this.getNodeCourses(node, this.semester, this.semClass, '', false)
+                this.getNodeCourses(node, this.offset, this.semester, this.semClass, '', false)
                     .then(response => {
+                        this.totalCourseCount = response.data.meta.page.total;
+                        this.offset = Math.ceil(response.data.meta.page.offset / this.limit);
                         this.courses = response.data.data;
                     });
             }
@@ -305,8 +330,10 @@ export default {
             }
         },
         showAllCourses(state) {
-            this.getNodeCourses(this.currentNode, this.semester, this.semClass, '', state)
+            this.getNodeCourses(this.currentNode, this.offset, this.semester, this.semClass, '', state)
                 .then(courses => {
+                    this.totalCourseCount = courses.data.meta.page.total;
+                    this.offset = Math.ceil(courses.data.meta.page.offset / this.limit);
                     this.courses = courses.data.data;
                     this.showingAllCourses = state;
                 });
@@ -326,8 +353,10 @@ export default {
             });
 
         if (this.withCourses) {
-            this.getNodeCourses(this.currentNode, this.semester, this.semClass)
+            this.getNodeCourses(this.currentNode, 0, this.semester, this.semClass)
                 .then(courses => {
+                    this.totalCourseCount = courses.data.meta.page.total;
+                    this.offset = 0;
                     this.courses = courses.data.data;
                 });
         }
diff --git a/resources/vue/components/tree/TreeNodeCourseInfo.vue b/resources/vue/components/tree/TreeNodeCourseInfo.vue
index db31d148c3f144ec4b221f91fd77667f5cf6f250..3f3777c933853066ba83eb23a58cc37e935f7544 100644
--- a/resources/vue/components/tree/TreeNodeCourseInfo.vue
+++ b/resources/vue/components/tree/TreeNodeCourseInfo.vue
@@ -1,33 +1,20 @@
 <template>
     <div class="studip-tree-child-description">
-        <template v-if="showingAllCourses">
-            <div v-translate="{ count: courseCount }" :translate-n="courseCount"
-                  translate-plural="<strong>%{count}</strong> Veranstaltungen auf dieser Ebene.">
-                <strong>Eine</strong> Veranstaltung auf dieser Ebene.
-            </div>
-        </template>
+        <studip-loading-skeleton v-if="isLoading" />
         <div v-else v-translate="{ count: courseCount }" :translate-n="courseCount"
-              translate-plural="<strong>%{count}</strong> Veranstaltungen auf dieser Ebene.">
-            <strong>Eine</strong> Veranstaltung auf dieser Ebene.
-        </div>
-        <template v-if="!showingAllCourses">
-            <div v-translate="{ count: allCourseCount }" :translate-n="allCourseCount"
-                  translate-plural="<strong>%{count}</strong> Veranstaltungen auf allen Unterebenen.">
-                <strong>Eine</strong> Veranstaltung auf allen Unterebenen.
-            </div>
-        </template>
-        <div v-else v-translate="{ count: allCourseCount }" :translate-n="allCourseCount"
-              translate-plural="<strong>%{count}</strong> Veranstaltungen auf allen Unterebenen.">
-            <strong>Eine</strong> Veranstaltung auf allen Unterebenen.
+             translate-plural="<strong>%{count}</strong> Veranstaltungen">
+            <strong>Eine</strong> Veranstaltung
         </div>
     </div>
 </template>
 
 <script>
 import { TreeMixin } from '../../mixins/TreeMixin';
+import StudipLoadingSkeleton from '../StudipLoadingSkeleton.vue';
 
 export default {
     name: 'TreeNodeCourseInfo',
+    components: { StudipLoadingSkeleton },
     mixins: [ TreeMixin ],
     props: {
         node: {
@@ -45,8 +32,8 @@ export default {
     },
     data() {
         return {
+            isLoading: false,
             courseCount: 0,
-            allCourseCount: 0,
             showingAllCourses: false
         }
     },
@@ -54,22 +41,22 @@ export default {
         showAllCourses(state) {
             this.showingAllCourses = state;
             this.$emit('showAllCourses', state);
+        },
+        loadNodeInfo(node) {
+            this.isLoading = true;
+            this.getNodeCourseInfo(node, this.semester, this.semClass)
+                .then(info => {
+                    this.courseCount = info?.data.courses;
+                    this.isLoading = false;
+                });
         }
     },
     mounted() {
-        this.getNodeCourseInfo(this.node, this.semester, this.semClass)
-            .then(info => {
-                this.courseCount = info?.data.courses;
-                this.allCourseCount = info?.data.allCourses;
-            });
+        this.loadNodeInfo(this.node);
     },
     watch: {
         node(newNode) {
-            this.getNodeCourseInfo(newNode, this.semester, this.semClass)
-                .then(info => {
-                    this.courseCount = info?.data.courses;
-                    this.allCourseCount = info?.data.allCourses;
-                });
+            this.loadNodeInfo(newNode);
         }
     }
 }
diff --git a/resources/vue/components/tree/TreeNodeTile.vue b/resources/vue/components/tree/TreeNodeTile.vue
index cbb0679eaeffeedb844b823abf4a2a5c0293e955..dab2bdf9ff698e0c4333cdd1873338ac45a85769 100644
--- a/resources/vue/components/tree/TreeNodeTile.vue
+++ b/resources/vue/components/tree/TreeNodeTile.vue
@@ -5,8 +5,11 @@
             {{ node.attributes.name }}
         </p>
 
-        <tree-node-course-info :node="node" :semester="semester"
-                               :sem-class="semClass"></tree-node-course-info>
+        <tree-node-course-info v-if="node.attributes.ancestors.length > 2" 
+                               :node="node"
+                               :semester="semester"
+                               :sem-class="semClass"
+        ></tree-node-course-info>
     </a>
 </template>
 
diff --git a/resources/vue/mixins/TreeMixin.js b/resources/vue/mixins/TreeMixin.js
index 9c4c859d7b092aba832c53186e52bb669b4c6a7b..4263eaf938d269906d771e679752511642a073d2 100644
--- a/resources/vue/mixins/TreeMixin.js
+++ b/resources/vue/mixins/TreeMixin.js
@@ -3,7 +3,10 @@ import axios from 'axios';
 export const TreeMixin = {
     data() {
         return {
-            showProgressIndicatorTimeout: 500
+            showProgressIndicatorTimeout: 500,
+            totalCourseCount: 0,
+            offset: 0,
+            limit: 50
         };
     },
     methods: {
@@ -22,9 +25,12 @@ export const TreeMixin = {
                 { params: parameters }
             );
         },
-        async getNodeCourses(node, semesterId = 'all', semClass = 0, searchterm = '', recursive = false, ids = []) {
+        async getNodeCourses(node, offset, semesterId = 'all', semClass = 0, searchterm = '', recursive = false, ids = []) {
             let parameters = {};
 
+            parameters['page[offset]'] = offset * this.limit;
+            parameters['page[limit]'] = this.limit;
+
             if (semesterId !== 'all' && semesterId !== '0') {
                 parameters['filter[semester]'] = semesterId;
             }
@@ -103,6 +109,15 @@ export const TreeMixin = {
                 { headers: { 'Content-Type': 'multipart/form-data' }}
             );
             STUDIP.Vue.emit('sort-tree-children', { parent: parentId, children: children });
+        },
+        updateOffset(newOffset) {
+            this.getNodeCourses(this.currentNode, newOffset, this.semester, this.semClass, '', this.showingAllCourses)
+                .then(courses => {
+                    this.courseCount = courses.data.meta.page.total;
+                    this.currentOffset = courses.data.meta.page.offset;
+                    this.offset = newOffset;
+                    this.courses = courses.data.data;
+                });
         }
     }
 }