diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
index 87d9f429075cad7a46a80dd55a82e3d01ea642c2..c2b765cfdf368764771b6ea7ff71a7bef3e8b5c2 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
@@ -69,7 +69,10 @@
         <DocumentationLoader />
       </template>
     </infinite-scrolling-date-sorted-c-r-u-d-iterator>
-    <absence-creation-dialog :absence-reasons="absenceReasons" />
+    <absence-creation-dialog
+      :absence-reasons="absenceReasons"
+      :affected-query="lastQuery"
+    />
   </div>
 </template>
 
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationDialog.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationDialog.vue
index 690b07972cd932a8d5eb0fd91609e0a662d829b0..e62c2ca4a22a314744a72a9feec45e439b9a1379 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationDialog.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationDialog.vue
@@ -96,7 +96,10 @@ import permissionsMixin from "aleksis.core/mixins/permissions.js";
 import mutateMixin from "aleksis.core/mixins/mutateMixin.js";
 import { DateTime } from "luxon";
 
-import { createAbsencesForPersons } from "./absenceCreation.graphql";
+import {
+  clearAbsencesForPersons,
+  createAbsencesForPersons,
+} from "./absenceCreation.graphql";
 
 export default {
   name: "AbsenceCreationDialog",
@@ -152,13 +155,17 @@ export default {
     confirm() {
       this.handleLoading(true);
       this.mutate(
-        createAbsencesForPersons,
+        this.absenceReason !== "present"
+          ? createAbsencesForPersons
+          : clearAbsencesForPersons,
         {
           persons: this.persons.map((p) => p.id),
           start: this.$toUTCISO(this.$parseISODate(this.startDate)),
           end: this.$toUTCISO(this.$parseISODate(this.endDate)),
-          comment: this.comment,
-          reason: this.absenceReason,
+          ...(this.absenceReason !== "present" && { comment: this.comment }),
+          ...(this.absenceReason !== "present" && {
+            reason: this.absenceReason,
+          }),
         },
         (storedDocumentations, incomingStatuses) => {
           incomingStatuses.forEach((newStatus) => {
@@ -172,7 +179,7 @@ export default {
               (part) => part.id === newStatus.id,
             );
 
-            participationStatus.absenceReason = newStatus.absenceReason;
+            participationStatus.absenceReason = newStatus?.absenceReason;
             participationStatus.isOptimistic = newStatus.isOptimistic;
           });
 
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationForm.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationForm.vue
index af7d0e86bf46df86150aa65621edebae5e1eb582..601c2916a64e0f5b2ae83d13dc797519acfc9908 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationForm.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationForm.vue
@@ -4,10 +4,9 @@
       <v-row>
         <div aria-required="true" class="full-width">
           <!-- FIXME Vue 3: clear-on-select -->
-          <v-autocomplete
+          <person-field
+            :gql-query="gqlQuery"
             :label="$t('forms.labels.persons')"
-            :items="allPersons"
-            item-text="fullName"
             return-object
             multiple
             chips
@@ -18,7 +17,6 @@
               ])
             "
             :value="persons"
-            :loading="$apollo.queries.allPersons.loading"
             @input="$emit('persons', $event)"
           />
         </div>
@@ -69,6 +67,7 @@
         <v-text-field
           :label="$t('forms.labels.comment')"
           :value="comment"
+          :disabled="absenceReason == 'present'"
           @input="$emit('comment', $event)"
         />
       </v-row>
@@ -76,6 +75,7 @@
         <div aria-required="true">
           <absence-reason-group-select
             :rules="$rules().required.build()"
+            allow-empty
             :value="absenceReason"
             :custom-absence-reasons="absenceReasons"
             @input="$emit('absence-reason', $event)"
@@ -89,7 +89,8 @@
 <script>
 import AbsenceReasonGroupSelect from "aleksis.apps.kolego/components/AbsenceReasonGroupSelect.vue";
 import DateTimeField from "aleksis.core/components/generic/forms/DateTimeField.vue";
-import { periodsByDay, persons } from "./absenceCreation.graphql";
+import PersonField from "aleksis.core/components/generic/forms/PersonField.vue";
+import { gqlPersons, periodsByDay } from "./absenceCreation.graphql";
 import formRulesMixin from "aleksis.core/mixins/formRulesMixin.js";
 import { DateTime } from "luxon";
 
@@ -98,6 +99,7 @@ export default {
   components: {
     AbsenceReasonGroupSelect,
     DateTimeField,
+    PersonField,
   },
   mixins: [formRulesMixin],
   emits: [
@@ -109,7 +111,6 @@ export default {
     "absence-reason",
   ],
   apollo: {
-    allPersons: persons,
     periodsByDay: {
       query: periodsByDay,
       result(_) {
@@ -146,6 +147,7 @@ export default {
   },
   data() {
     return {
+      gqlQuery: gqlPersons,
       startDT: DateTime.fromISO(this.startDate),
       endDT: DateTime.fromISO(this.endDate),
       startPeriods: false,
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceCreation.graphql b/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceCreation.graphql
index e164d0868c4bd378416941becb0e1e45a88eaaa9..34a22cef6431fd15450e48b40d7ce1d94553fb29 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceCreation.graphql
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceCreation.graphql
@@ -1,8 +1,9 @@
 # Uses core persons query
-query persons {
-  allPersons: absenceCreationPersons {
+query gqlPersons {
+  items: absenceCreationPersons {
     id
     fullName
+    shortName
   }
 }
 
@@ -70,3 +71,23 @@ mutation createAbsencesForPersons(
     }
   }
 }
+
+mutation clearAbsencesForPersons(
+  $persons: [ID]!
+  $start: DateTime!
+  $end: DateTime!
+) {
+  clearAbsencesForPersons(persons: $persons, start: $start, end: $end) {
+    ok
+    items: participationStatuses {
+      id
+      isOptimistic
+      relatedDocumentation {
+        id
+      }
+      absenceReason {
+        id
+      }
+    }
+  }
+}
diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index 2dd3deac4fbc03f3e85b4d791170f09eaf5054e3..9b4d5d2e302c72566a4a6851826c8d2669cf2b77 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -118,7 +118,7 @@ class Documentation(CalendarEvent):
             return self.course.groups.all()
 
     def get_teachers_short_names(self) -> list[str]:
-        return [teacher.short_name or teacher.name for teacher in self.teachers.all()]
+        return [teacher.short_name or teacher.full_name for teacher in self.teachers.all()]
 
     def __str__(self) -> str:
         start_datetime = CalendarEvent.value_start_datetime(self)
@@ -498,6 +498,29 @@ class ParticipationStatus(CalendarEvent):
 
         return participation_statuses
 
+    @classmethod
+    def clear_absence_by_datetimes(
+        cls, person: Person, start: datetime, end: datetime
+    ) -> list["ParticipationStatus"]:
+        participation_statuses = []
+
+        events = cls.get_single_events(
+            start,
+            end,
+            None,
+            {"person": person},
+            with_reference_object=True,
+        )
+
+        for event in events:
+            participation_status = event["REFERENCE_OBJECT"]
+            participation_status.absence_reason = None
+            participation_status.base_absence = None
+            participation_status.save()
+            participation_statuses.append(participation_status)
+
+        return participation_statuses
+
     def fill_from_kolego(self, kolego_absence: KolegoAbsence):
         """Take over data from a Kolego absence."""
         self.base_absence = kolego_absence
diff --git a/aleksis/apps/alsijil/schema/__init__.py b/aleksis/apps/alsijil/schema/__init__.py
index a8e830da046e4679d30c9695a8b4d6ae10e0e2f1..0c75517fd62d63d0c181156c9d2529a711ff7590 100644
--- a/aleksis/apps/alsijil/schema/__init__.py
+++ b/aleksis/apps/alsijil/schema/__init__.py
@@ -26,6 +26,7 @@ from aleksis.core.util.core_helpers import (
 from ..model_extensions import annotate_person_statistics_for_school_term
 from ..models import Documentation, ExtraMark, NewPersonalNote, ParticipationStatus
 from .absences import (
+    AbsencesForPersonsClearMutation,
     AbsencesForPersonsCreateMutation,
 )
 from .documentation import (
@@ -394,6 +395,7 @@ class Mutation(graphene.ObjectType):
     touch_documentation = TouchDocumentationMutation.Field()
     update_participation_statuses = ParticipationStatusBatchPatchMutation.Field()
     create_absences_for_persons = AbsencesForPersonsCreateMutation.Field()
+    clear_absences_for_persons = AbsencesForPersonsClearMutation.Field()
     extend_participation_statuses = ExtendParticipationStatusToAbsenceBatchMutation.Field()
 
     create_extra_marks = ExtraMarkBatchCreateMutation.Field()
diff --git a/aleksis/apps/alsijil/schema/absences.py b/aleksis/apps/alsijil/schema/absences.py
index eea8b075b3e1ba2a0e6011e4b7e33e6df4f09ed4..8a729f0a4ae10624c9522fb27a8a4166af78b40a 100644
--- a/aleksis/apps/alsijil/schema/absences.py
+++ b/aleksis/apps/alsijil/schema/absences.py
@@ -56,3 +56,44 @@ class AbsencesForPersonsCreateMutation(graphene.Mutation):
         return AbsencesForPersonsCreateMutation(
             ok=True, participation_statuses=participation_statuses
         )
+
+
+class AbsencesForPersonsClearMutation(graphene.Mutation):
+    class Arguments:
+        persons = graphene.List(graphene.ID, required=True)
+        start = graphene.DateTime(required=True)
+        end = graphene.DateTime(required=True)
+
+    ok = graphene.Boolean()
+    participation_statuses = graphene.List(ParticipationStatusType)
+
+    @classmethod
+    def mutate(
+        cls,
+        root,
+        info,
+        persons: list[str | int],
+        start: datetime.datetime,
+        end: datetime.datetime,
+    ):
+        participation_statuses = []
+
+        persons = Person.objects.filter(pk__in=persons)
+
+        for person in persons:
+            if not info.context.user.has_perm("alsijil.register_absence_rule", person):
+                raise PermissionDenied()
+
+            participation_statuses += ParticipationStatus.clear_absence_by_datetimes(
+                person=person, start=start, end=end
+            )
+
+            Absence.clear_or_extend_absences_in_timespan(
+                person=person,
+                datetime_start=start,
+                datetime_end=end,
+            )
+
+        return AbsencesForPersonsClearMutation(
+            ok=True, participation_statuses=participation_statuses
+        )