diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonNotes.vue b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonNotes.vue
index af954823b167a8a9d3c95c419e4896609dabb812..a412d39deed9232c8668e60716a3825096394347 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonNotes.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonNotes.vue
@@ -1,178 +1,238 @@
 <script setup>
 import AbsenceReasonChip from "aleksis.apps.kolego/components/AbsenceReasonChip.vue";
 import ExtraMarkChip from "../../extra_marks/ExtraMarkChip.vue";
+import ExtraMarksNote from "../personal_notes/ExtraMarksNote.vue";
 import TardinessChip from "../absences/TardinessChip.vue";
 import PersonalNoteChip from "../personal_notes/PersonalNoteChip.vue";
+import TextNoteCard from "../personal_notes/TextNoteCard.vue";
 </script>
 
 <template>
-  <div
-    class="d-flex align-center justify-space-between justify-md-end flex-wrap gap"
-  >
-    <v-chip
-      dense
-      color="success"
-      outlined
-      v-if="total > 0 && documentation.canViewParticipationStatus"
+  <div>
+    <div
+      class="d-flex align-center justify-space-between justify-md-end flex-wrap gap"
+      v-if="compact || documentation.canViewParticipationStatus"
     >
-      {{
-        $t("alsijil.coursebook.participations.present_number", {
-          present,
-          total,
-        })
-      }}
-    </v-chip>
-    <v-chip
-      dense
-      color="success"
-      outlined
-      @click="$emit('open')"
-      v-bind="dialogActivator.attrs"
-      v-on="dialogActivator.on"
-      v-else-if="
-        total == 1 && present == 1 && !documentation.canViewParticipationStatus
-      "
-    >
-      {{ $t("alsijil.coursebook.participations.present") }}
-    </v-chip>
-
-    <template v-if="documentation.canViewParticipationStatus">
-      <absence-reason-chip
-        v-for="[reasonId, participations] in Object.entries(absences)"
-        :key="'reason-' + reasonId"
-        :absence-reason="participations[0].absenceReason"
+      <v-chip
         dense
+        color="success"
+        outlined
+        v-if="total > 0 && documentation.canViewParticipationStatus"
       >
-        <template #append>
-          <span
-            >:
-            <span>
-              {{
-                participations
-                  .slice(0, 5)
-                  .map((participation) => participation.person.firstName)
-                  .join(", ")
-              }}
-            </span>
-            <span v-if="participations.length > 5">
-              <!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
-              +{{ participations.length - 5 }}
-              <!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
-            </span>
-          </span>
-        </template>
-      </absence-reason-chip>
-    </template>
-    <template v-else>
-      <absence-reason-chip
-        v-for="[reasonId, participations] in Object.entries(absences)"
-        :key="'reason-' + reasonId"
-        :absence-reason="participations[0].absenceReason"
+        {{
+          $t("alsijil.coursebook.participations.present_number", {
+            present,
+            total,
+          })
+        }}
+      </v-chip>
+      <v-chip
         dense
+        color="success"
+        outlined
         @click="$emit('open')"
         v-bind="dialogActivator.attrs"
         v-on="dialogActivator.on"
-      />
-    </template>
-
-    <template v-if="documentation.canViewParticipationStatus">
-      <extra-mark-chip
-        v-for="[markId, [mark, ...participations]] in Object.entries(
-          extraMarkChips,
-        )"
-        :key="'extra-mark-' + markId"
-        :extra-mark="mark"
-        dense
+        v-else-if="
+          total == 1 &&
+          present == 1 &&
+          !documentation.canViewParticipationStatus
+        "
       >
-        <template #append>
-          <span
-            >:
-            <span>
+        {{ $t("alsijil.coursebook.participations.present") }}
+      </v-chip>
+
+      <template v-if="documentation.canViewParticipationStatus">
+        <absence-reason-chip
+          v-for="[reasonId, participations] in Object.entries(absences)"
+          :key="'reason-' + reasonId"
+          :absence-reason="participations[0].absenceReason"
+          dense
+        >
+          <template #append>
+            <span
+              >:
+              <span>
+                {{
+                  participations
+                    .slice(0, 5)
+                    .map((participation) => participation.person.firstName)
+                    .join(", ")
+                }}
+              </span>
+              <span v-if="participations.length > 5">
+                <!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
+                +{{ participations.length - 5 }}
+                <!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
+              </span>
+            </span>
+          </template>
+        </absence-reason-chip>
+      </template>
+      <template v-else>
+        <absence-reason-chip
+          v-for="[reasonId, participations] in Object.entries(absences)"
+          :key="'reason-' + reasonId"
+          :absence-reason="participations[0].absenceReason"
+          dense
+          @click="$emit('open')"
+          v-bind="dialogActivator.attrs"
+          v-on="dialogActivator.on"
+        />
+      </template>
+
+      <template v-if="documentation.canViewParticipationStatus">
+        <extra-mark-chip
+          v-for="[markId, [mark, ...participations]] in Object.entries(
+            extraMarkChips,
+          )"
+          :key="'extra-mark-' + markId"
+          :extra-mark="mark"
+          dense
+        >
+          <template #append>
+            <span
+              >:
+              <span>
+                {{
+                  participations
+                    .slice(0, 5)
+                    .map((participation) => participation.person.firstName)
+                    .join(", ")
+                }}
+              </span>
+              <span v-if="participations.length > 5">
+                <!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
+                +{{ participations.length - 5 }}
+                <!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
+              </span>
+            </span>
+          </template>
+        </extra-mark-chip>
+      </template>
+      <template v-else>
+        <extra-mark-chip
+          v-for="[markId, [mark, ...participations]] in Object.entries(
+            extraMarkChips,
+          )"
+          :key="'extra-mark-' + markId"
+          :extra-mark="mark"
+          dense
+          @click="$emit('open')"
+          v-bind="dialogActivator.attrs"
+          v-on="dialogActivator.on"
+        />
+      </template>
+
+      <template v-if="documentation.canViewParticipationStatus">
+        <tardiness-chip v-if="tardyParticipations.length > 0">
+          <template #default>
+            {{ $t("alsijil.personal_notes.late") }}
+          </template>
+
+          <template #append>
+            <span
+              >:
               {{
-                participations
+                tardyParticipations
                   .slice(0, 5)
                   .map((participation) => participation.person.firstName)
                   .join(", ")
               }}
-            </span>
-            <span v-if="participations.length > 5">
-              <!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
-              +{{ participations.length - 5 }}
-              <!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
-            </span>
-          </span>
-        </template>
-      </extra-mark-chip>
-    </template>
-    <template v-else>
-      <extra-mark-chip
-        v-for="[markId, [mark, ...participations]] in Object.entries(
-          extraMarkChips,
-        )"
-        :key="'extra-mark-' + markId"
-        :extra-mark="mark"
-        dense
-        @click="$emit('open')"
-        v-bind="dialogActivator.attrs"
-        v-on="dialogActivator.on"
-      />
-    </template>
-
-    <template v-if="documentation.canViewParticipationStatus">
-      <tardiness-chip v-if="tardyParticipations.length > 0">
-        <template #default>
-          {{ $t("alsijil.personal_notes.late") }}
-        </template>
 
-        <template #append>
-          <span
-            >:
-            {{
-              tardyParticipations
-                .slice(0, 5)
-                .map((participation) => participation.person.firstName)
-                .join(", ")
-            }}
-
-            <span v-if="tardyParticipations.length > 5">
-              <!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
-              +{{ tardyParticipations.length - 5 }}
-              <!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
+              <span v-if="tardyParticipations.length > 5">
+                <!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
+                +{{ tardyParticipations.length - 5 }}
+                <!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
+              </span>
             </span>
-          </span>
-        </template>
-      </tardiness-chip>
-    </template>
-    <template v-else>
-      <tardiness-chip
-        v-if="tardyParticipations.length > 0"
-        :tardiness="
-          tardyParticipations.length == 1
-            ? tardyParticipations[0].tardiness
-            : undefined
-        "
-        @click="$emit('open')"
-        v-bind="dialogActivator.attrs"
-        v-on="dialogActivator.on"
-      />
-    </template>
+          </template>
+        </tardiness-chip>
+      </template>
+      <template v-else>
+        <tardiness-chip
+          v-if="tardyParticipations.length > 0"
+          :tardiness="
+            tardyParticipations.length == 1
+              ? tardyParticipations[0].tardiness
+              : undefined
+          "
+          @click="$emit('open')"
+          v-bind="dialogActivator.attrs"
+          v-on="dialogActivator.on"
+        />
+      </template>
 
-    <template v-if="!documentation.canViewParticipationStatus && total == 1">
-      <personal-note-chip
-        v-for="note in documentation?.participations[0]?.notesWithNote"
-        :key="'text-note-note-' + note.id"
-        :note="note"
-        @click="$emit('open')"
-        v-bind="dialogActivator.attrs"
-        v-on="dialogActivator.on"
+      <template v-if="!documentation.canViewParticipationStatus && total == 1">
+        <personal-note-chip
+          v-for="note in documentation?.participations[0]?.notesWithNote"
+          :key="'text-note-note-' + note.id"
+          :note="note"
+          @click="$emit('open')"
+          v-bind="dialogActivator.attrs"
+          v-on="dialogActivator.on"
+        />
+      </template>
+
+      <manage-students-trigger
+        v-if="documentation.canEditParticipationStatus"
+        :label-key="manageStudentsLabelKey"
+        v-bind="documentationPartProps"
       />
-    </template>
+    </div>
 
-    <manage-students-trigger
-      v-if="documentation.canEditParticipationStatus"
-      :label-key="manageStudentsLabelKey"
-      v-bind="documentationPartProps"
-    />
+    <!-- not compact -->
+    <div class="main-body" v-else>
+      <template
+        v-if="
+          tardyParticipations.length > 0 || Object.entries(absences).length > 0
+        "
+      >
+        <v-divider />
+        <div
+          class="d-flex align-center justify-space-between justify-md-end flex-wrap gap"
+        >
+          <tardiness-chip
+            v-if="tardyParticipations.length > 0"
+            :tardiness="
+              tardyParticipations.length == 1
+                ? tardyParticipations[0].tardiness
+                : undefined
+            "
+          />
+          <absence-reason-chip
+            v-for="[reasonId, participations] in Object.entries(absences)"
+            :key="'reason-' + reasonId"
+            :absence-reason="participations[0].absenceReason"
+            dense
+          />
+        </div>
+      </template>
+      <template v-if="total == 1">
+        <v-divider />
+        <extra-marks-note
+          v-bind="documentationPartProps"
+          :participation="documentation?.participations[0]"
+          :value="documentation?.participations[0].notesWithExtraMark"
+          :disabled="true"
+        />
+      </template>
+      <template
+        v-if="
+          total == 1 &&
+          documentation?.participations[0]?.notesWithNote.length > 0
+        "
+      >
+        <v-divider />
+        <div>
+          <text-note-card
+            v-for="note in documentation?.participations[0]?.notesWithNote"
+            :key="'text-note-note-' + note.id"
+            :note="note"
+          />
+        </div>
+      </template>
+    </div>
   </div>
 </template>
 
@@ -257,4 +317,9 @@ export default {
 .gap {
   gap: 0.25em;
 }
+.main-body {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr);
+  gap: 1em;
+}
 </style>
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/personal_notes/ExtraMarkNoteCheckbox.vue b/aleksis/apps/alsijil/frontend/components/coursebook/personal_notes/ExtraMarkNoteCheckbox.vue
index 1f31f9ee1cf6c557ee2fe7b86134793629f9063f..e6985a1f854b9915d6effb282674b0ca9bd478f0 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/personal_notes/ExtraMarkNoteCheckbox.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/personal_notes/ExtraMarkNoteCheckbox.vue
@@ -88,7 +88,7 @@ export default {
     :label="value.name"
     :value="value.id"
     v-model="model"
-    :disabled="loading"
+    :disabled="$attrs?.disabled || loading"
     :true-value="true"
     :false-value="false"
   >
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/personal_notes/ExtraMarksNote.vue b/aleksis/apps/alsijil/frontend/components/coursebook/personal_notes/ExtraMarksNote.vue
index fd5f2c6d20597375e3f1e126cb7b78c7835adbbe..f6bed5bb8f03e7442aebad04ec01346eee801fbd 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/personal_notes/ExtraMarksNote.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/personal_notes/ExtraMarksNote.vue
@@ -20,7 +20,7 @@ export default {
     <extra-mark-note-checkbox
       v-for="extraMark in extraMarks"
       :key="'checkbox-extramark-' + extraMark.id"
-      v-bind="personalNoteRelatedProps"
+      v-bind="{ ...personalNoteRelatedProps, ...$attrs }"
       :value="extraMark"
       :personal-note="value.find((pn) => pn.extraMark.id === extraMark.id)"
     />
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/personal_notes/TextNoteCard.vue b/aleksis/apps/alsijil/frontend/components/coursebook/personal_notes/TextNoteCard.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f180603b7563f36f5ecd59bcce134d586bae0bda
--- /dev/null
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/personal_notes/TextNoteCard.vue
@@ -0,0 +1,27 @@
+<template>
+  <v-card
+    outlined
+    dense
+    rounded="lg"
+    class="mb-2"
+    v-bind="$attrs"
+    v-on="$listeners"
+  >
+    <v-card-title class="text-subtitle-2 pb-1 font-weight-medium">
+      {{ $t("alsijil.personal_notes.card.title") }}
+    </v-card-title>
+    <v-card-text>{{ note.note || "–" }}</v-card-text>
+  </v-card>
+</template>
+
+<script>
+export default {
+  name: "TextNoteCard",
+  props: {
+    note: {
+      type: Object,
+      required: true,
+    },
+  },
+};
+</script>
diff --git a/aleksis/apps/alsijil/frontend/messages/en.json b/aleksis/apps/alsijil/frontend/messages/en.json
index 0df412fbeed71e3cb038bb2e3ca93841caad8021..706ffbea77429f694154d96390aab829148e35db 100644
--- a/aleksis/apps/alsijil/frontend/messages/en.json
+++ b/aleksis/apps/alsijil/frontend/messages/en.json
@@ -123,6 +123,9 @@
       }
     },
     "personal_notes": {
+      "card": {
+        "title": "Personal note"
+      },
       "note": "Note",
       "create_personal_note": "Add another note",
       "tardiness": "Tardiness",