diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
index e6098ee01021742369909e83210135c47f572473..a9f4fb0c7411407a5e98cdfe4a386f3b2c7cf678 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
@@ -1,4 +1,5 @@
 <script>
+import AbsenceReasonButtons from "aleksis.apps.kolego/components/AbsenceReasonButtons.vue";
 import AbsenceReasonChip from "aleksis.apps.kolego/components/AbsenceReasonChip.vue";
 import AbsenceReasonGroupSelect from "aleksis.apps.kolego/components/AbsenceReasonGroupSelect.vue";
 import CancelButton from "aleksis.core/components/generic/buttons/CancelButton.vue";
@@ -15,6 +16,7 @@ export default {
   components: {
     AbsenceReasonChip,
     AbsenceReasonGroupSelect,
+    AbsenceReasonButtons,
     CancelButton,
     LessonInformation,
     MobileFullscreenDialog,
@@ -25,6 +27,7 @@ export default {
     return {
       dialog: false,
       search: "",
+      loadSelected: false,
       selected: [],
       isExpanded: false,
     };
@@ -42,29 +45,29 @@ export default {
     },
   },
   methods: {
-    sendToServer(participation, field, value) {
+    sendToServer(participations, field, value) {
       if (field !== "absenceReason") return;
 
       this.mutate(
         updateParticipationStatuses,
         {
-          input: [
-            {
-              id: participation.id,
-              absenceReason: value === "present" ? null : value,
-            },
-          ],
+          input: participations.map((participation) => ({
+            id: participation.id,
+            absenceReason: value === "present" ? null : value,
+          })),
         },
         (storedDocumentations, incomingStatuses) => {
-          const newStatus = incomingStatuses[0];
           const documentation = storedDocumentations.find(
-            (doc) => doc.id === newStatus.relatedDocumentation.id,
+            (doc) => doc.id === this.documentation.id,
           );
-          const participationStatus = documentation.participations.find(
-            (part) => part.id === newStatus.id,
-          );
-          participationStatus.absenceReason = newStatus.absenceReason;
-          participationStatus.isOptimistic = newStatus.isOptimistic;
+
+          incomingStatuses.forEach((newStatus) => {
+            const participationStatus = documentation.participations.find(
+              (part) => part.id === newStatus.id,
+            );
+            participationStatus.absenceReason = newStatus.absenceReason;
+            participationStatus.isOptimistic = newStatus.isOptimistic;
+          });
 
           return storedDocumentations;
         },
@@ -94,6 +97,16 @@ export default {
         // },
       );
     },
+    handleMultipleAction(absenceReasonId) {
+      this.loadSelected = true;
+      this.sendToServer(this.selected, "absenceReason", absenceReasonId);
+      this.$once("save", this.resetMultipleAction);
+    },
+    resetMultipleAction() {
+      this.loadSelected = false;
+      this.$set(this.selected, []);
+      this.$refs.iterator.selected = [];
+    },
   },
 };
 </script>
@@ -110,27 +123,36 @@ export default {
     </template>
 
     <template #title>
-      <lesson-information v-bind="documentationPartProps" />
-      <v-slide-x-transition leave-absolute>
+      <lesson-information v-bind="documentationPartProps" :compact="false" />
+      <v-scroll-x-transition leave-absolute>
         <v-text-field
           v-show="!isExpanded"
           type="search"
           v-model="search"
           clearable
           rounded
-          filled
           hide-details
           single-line
           prepend-inner-icon="$search"
           dense
           outlined
           :placeholder="$t('actions.search')"
-          class="pt-4"
+          class="pt-4 full-width"
         />
-      </v-slide-x-transition>
+      </v-scroll-x-transition>
+      <v-scroll-x-transition>
+        <div v-show="selected.length > 0" class="full-width mt-4">
+          <absence-reason-buttons
+            allow-empty
+            empty-value="present"
+            @input="handleMultipleAction"
+          />
+        </div>
+      </v-scroll-x-transition>
     </template>
     <template #content>
       <slide-iterator
+        ref="iterator"
         v-model="selected"
         :items="items"
         :search="search"
@@ -138,7 +160,9 @@ export default {
           (item) => 'documentation-' + documentation.id + '-student-' + item.id
         "
         :is-expanded.sync="isExpanded"
-        :loading="loadingIndicator"
+        :loading="loadingIndicator || loadSelected"
+        :load-only-selected="loadSelected"
+        :disabled="loading"
       >
         <template #listItemContent="{ item }">
           <v-list-item-title>
@@ -167,7 +191,7 @@ export default {
               empty-value="present"
               :loadSelectedChip="loading"
               :value="item.absenceReason?.id || 'present'"
-              @input="sendToServer(item, 'absenceReason', $event)"
+              @input="sendToServer([item], 'absenceReason', $event)"
             />
           </v-card-text>
         </template>
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/participationStatus.graphql b/aleksis/apps/alsijil/frontend/components/coursebook/absences/participationStatus.graphql
index 4c3f8df66e8236bb126aff29ccf8361931b35f8e..2f15ef02dbc47faa9d0787b21b13f3ba9d1ad3a6 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/participationStatus.graphql
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/participationStatus.graphql
@@ -12,6 +12,7 @@ mutation updateParticipationStatuses(
         id
         name
         shortName
+        colour
       }
     }
   }
@@ -31,6 +32,7 @@ mutation touchDocumentation($documentationId: ID!) {
           id
           name
           shortName
+          colour
         }
         isOptimistic
       }
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/coursebook.graphql b/aleksis/apps/alsijil/frontend/components/coursebook/coursebook.graphql
index b93cd7844ee5bff8cf3e4d5c0a065bc2f1bb7166..1e00bab2ee180c843fa99b3ec0b6e5574bb4409d 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/coursebook.graphql
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/coursebook.graphql
@@ -76,6 +76,7 @@ query documentationsForCoursebook(
         id
         name
         shortName
+        colour
       }
       isOptimistic
     }
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonInformation.vue b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonInformation.vue
index 09a04bcb67c6ae618fa0b1546a0171af30323885..652609dccaf430d3a4ab138f80ee2f810b84b4af 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonInformation.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonInformation.vue
@@ -61,7 +61,7 @@ import PersonChip from "aleksis.core/components/person/PersonChip.vue";
         v-for="teacher in documentation.teachers"
         :key="documentation.id + '-teacher-' + teacher.id"
         :person="teacher"
-        no-link
+        :no-link="compact"
         v-bind="compact ? dialogActivator.attrs : {}"
         v-on="compact ? dialogActivator.on : {}"
       />
@@ -69,7 +69,7 @@ import PersonChip from "aleksis.core/components/person/PersonChip.vue";
         v-for="teacher in amendedTeachers"
         :key="documentation.id + '-amendedTeacher-' + teacher.id"
         :person="teacher"
-        no-link
+        :no-link="compact"
         v-bind="compact ? dialogActivator.attrs : {}"
         v-on="compact ? dialogActivator.on : {}"
         class="text-decoration-line-through"
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonNotes.vue b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonNotes.vue
index 8f40f71b60199a8c10e577d0ae006fbb1af5a7c5..880e92f4c03eb41a042f1ace474611de0ab5617e 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonNotes.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonNotes.vue
@@ -1,33 +1,24 @@
+<script setup>
+import AbsenceReasonChip from "aleksis.apps.kolego/components/AbsenceReasonChip.vue";
+</script>
+
 <template>
   <div
     class="d-flex align-center justify-space-between justify-md-end flex-wrap gap"
   >
-    <!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
-    <v-chip dense color="success">
-      <v-chip small dense class="mr-2" color="green darken-3 white--text">
-        {{ documentation.participations.length }}
-      </v-chip>
-      Schüler
-    </v-chip>
-    <v-chip dense color="warning">
-      <v-chip small dense class="mr-2" color="orange darken-3 white--text"
-        >3</v-chip
-      >
-      entschuldigt
+    <v-chip dense color="success" outlined v-if="total > 0">
+      {{ $t("alsijil.coursebook.present_number", { present, total })}}
     </v-chip>
-    <v-chip dense color="error">
-      <v-chip small dense class="mr-2" color="red darken-3 white--text"
-        >1</v-chip
-      >
-      unentschuldigt
-    </v-chip>
-    <v-chip dense color="grey lighten-1">
-      <v-chip small dense class="mr-2" color="grey darken-1 white--text"
-        >4</v-chip
-      >
-      Hausaufgaben vergessen
-    </v-chip>
-    <!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
+    <absence-reason-chip
+      v-for="participation in absences"
+      :absence-reason="participation.absenceReason"
+      dense
+    >
+      <template #prepend>
+        {{ participation.person.fullName }}:
+      </template>
+    </absence-reason-chip>
+
     <manage-students-trigger v-bind="documentationPartProps" />
   </div>
 </template>
@@ -40,6 +31,18 @@ export default {
   name: "LessonNotes",
   components: { ManageStudentsTrigger },
   mixins: [documentationPartMixin],
+  computed: {
+    total() {
+      return this.documentation.participations.length;
+    },
+    present() {
+      return this.documentation.participations.filter(p => p.absenceReason === null).length;
+    },
+    absences() {
+      // Get all course attendants who have an absence reason
+      return this.documentation.participations.filter(p => p.absenceReason !== null);
+    },
+  },
 };
 </script>
 
diff --git a/aleksis/apps/alsijil/frontend/messages/de.json b/aleksis/apps/alsijil/frontend/messages/de.json
index 672bfe5f0d806921482505eb1cde16c5ebef9b1c..31ae2d9763a98f946aa896a9ab79d5fc8d514a0f 100644
--- a/aleksis/apps/alsijil/frontend/messages/de.json
+++ b/aleksis/apps/alsijil/frontend/messages/de.json
@@ -49,13 +49,27 @@
           }
         }
       },
-      "title_plural": "Kursbuch"
+      "title_plural": "Kursbuch",
+      "present_number": "{present}/{total} anwesend"
     },
     "excuse_types": {
       "menu_title": "Entschuldigungsarten"
     },
     "extra_marks": {
-      "menu_title": "Zusätzliche Markierungen"
+      "menu_title": "Zusätzliche Markierungen",
+      "create": "Markierung erstellen",
+      "name": "Markierung",
+      "short_name": "Abkürzung",
+      "colour_fg": "Schriftfarbe",
+      "colour_bg": "Hintergrundfarbe",
+      "show_in_coursebook": "In Kursbuch-Ãœbersicht zeigen",
+      "show_in_coursebook_helptext": "Wenn aktiviert tauchen diese Markierungen in den Zeilen im Kursbuch auf."
+    },
+    "personal_notes": {
+      "note": "Notiz",
+      "create_personal_note": "Weitere Notiz",
+      "confirm_delete": "Notiz wirklich löschen?",
+      "confirm_delete_explanation": "Die Notiz \"{note}\" für {name} wird entfernt."
     },
     "group_roles": {
       "menu_title_assign": "Gruppenrollen zuweisen",
diff --git a/aleksis/apps/alsijil/frontend/messages/en.json b/aleksis/apps/alsijil/frontend/messages/en.json
index 4f17201251a67936819498514b54d3ca3b592fbe..71a509cfec66659437760a1c2ab2fc41ad35cd3c 100644
--- a/aleksis/apps/alsijil/frontend/messages/en.json
+++ b/aleksis/apps/alsijil/frontend/messages/en.json
@@ -74,6 +74,7 @@
         "courses": "Courses",
         "filter_for_obj": "Filter for group and course"
       },
+      "present_number": "{present}/{total} present",
       "no_data": "No lessons for the selected groups and courses in this period",
       "no_results": "No search results for {search}"
     }