diff --git a/aleksis/core/frontend/app/vuetify.js b/aleksis/core/frontend/app/vuetify.js
index 56eb8effa2da7cd552ad4aed5455f4acd7911df6..f80eb0ac531c075935acdb2249ec5c1676267891 100644
--- a/aleksis/core/frontend/app/vuetify.js
+++ b/aleksis/core/frontend/app/vuetify.js
@@ -28,6 +28,7 @@ const vuetifyOpts = {
       filterEmpty: "mdi-filter-outline",
       filterSet: "mdi-filter",
       send: "mdi-send-outline",
+      holidays: "mdi-calendar-weekend-outline"
     },
   },
 };
diff --git a/aleksis/core/frontend/components/holiday/HolidayInlineList.vue b/aleksis/core/frontend/components/holiday/HolidayInlineList.vue
new file mode 100644
index 0000000000000000000000000000000000000000..07126079b04b793b54a223ec25c49100f01b4dd5
--- /dev/null
+++ b/aleksis/core/frontend/components/holiday/HolidayInlineList.vue
@@ -0,0 +1,118 @@
+<script setup>
+import InlineCRUDList from "../generic/InlineCRUDList.vue";
+import DateField from "../generic/forms/DateField.vue";
+</script>
+
+<template>
+  <inline-c-r-u-d-list
+      :headers="headers"
+      :i18n-key="i18nKey"
+      create-item-i18n-key="holidays.create_holiday"
+      :gql-query="gqlQuery"
+      :gql-create-mutation="gqlCreateMutation"
+      :gql-patch-mutation="gqlPatchMutation"
+      :gql-delete-mutation="gqlDeleteMutation"
+      :gql-delete-multiple-mutation="gqlDeleteMultipleMutation"
+      :default-item="defaultItem"
+      ref="crudList"
+  >
+    <template #holidayName.field="{ attrs, on, isCreate }">
+      <div aria-required="true">
+        <v-text-field
+            v-bind="attrs"
+            v-on="on"
+            required
+            :rules="required"
+        ></v-text-field>
+      </div>
+    </template>
+
+    <template #dateStart="{ item }">
+      {{ $d(new Date(item.dateStart), "short") }}
+    </template>
+    <template #dateStart.field="{ attrs, on, item, isCreate }">
+      <div aria-required="true">
+        <date-field
+            v-bind="attrs"
+            v-on="on"
+            :rules="required"
+            :max="item ? item.dateEnd : undefined"
+            @input="updateEndDate($event, item, isCreate)"
+        ></date-field>
+      </div>
+    </template>
+
+    <template #dateEnd="{ item }">
+      {{ $d(new Date(item.dateEnd), "short") }}
+    </template>
+    <template #dateEnd.field="{ attrs, on, item }">
+      <div aria-required="true">
+        <date-field
+            v-bind="attrs"
+            v-on="on"
+            required
+            :rules="required"
+            :min="item ? item.dateStart : undefined"
+        ></date-field>
+      </div>
+    </template>
+  </inline-c-r-u-d-list>
+</template>
+
+<script>
+import {holidays, createHoliday, deleteHoliday, deleteHolidays, updateHolidays} from "./holiday.graphql";
+
+export default {
+  name: "HolidayInlineList",
+  data() {
+    return {
+      headers: [
+        {
+          text: this.$t("holidays.holiday_name"),
+          value: "holidayName",
+        },
+        {
+          text: this.$t("holidays.date_start"),
+          value: "dateStart",
+        },
+        {
+          text: this.$t("holidays.date_end"),
+          value: "dateEnd",
+        },
+      ],
+      i18nKey: "holidays",
+      gqlQuery: holidays,
+      gqlCreateMutation: createHoliday,
+      gqlPatchMutation: updateHolidays,
+      gqlDeleteMutation: deleteHoliday,
+      gqlDeleteMultipleMutation: deleteHolidays,
+      defaultItem: {
+        holidayName: "",
+        dateStart: null,
+        dateEnd: null,
+      },
+      required: [(value) => !!value || this.$t("forms.errors.required")],
+    };
+  },
+  methods: {
+    updateEndDate(newStartDate, item, isCreate) {
+      console.log("method called", item)
+      let start = new Date(newStartDate);
+      console.log(start)
+      if (!item.endDate) {
+        if (isCreate) {
+          this.$refs.crudList.createModel.dateEnd = newStartDate;
+          console.log("Changed of createmodel");
+        } else {
+          this.$refs.crudList.editableItems.find(holiday => holiday.id === item.id)[0].dateEnd = newStartDate;
+          console.log("Changed of editableitems");
+        }
+      } else {
+        console.log(item, newStartDate);
+      }
+    }
+  },
+};
+</script>
+
+<style scoped></style>
diff --git a/aleksis/core/frontend/components/holiday/holiday.graphql b/aleksis/core/frontend/components/holiday/holiday.graphql
new file mode 100644
index 0000000000000000000000000000000000000000..0b4742c3f304671c199c2ad9aa5f5cd95445b666
--- /dev/null
+++ b/aleksis/core/frontend/components/holiday/holiday.graphql
@@ -0,0 +1,48 @@
+query holidays($orderBy: [String], $filters: JSONString) {
+    items: holidays(orderBy: $orderBy, filters: $filters) {
+        id
+        holidayName
+        dateStart
+        dateEnd
+        canEdit
+        canDelete
+    }
+}
+
+mutation createHoliday($input: CreateHolidayInput!) {
+    createHoliday(input: $input) {
+        holiday {
+            id
+            holidayName
+            dateStart
+            dateEnd
+            canEdit
+            canDelete
+        }
+    }
+}
+
+mutation deleteHoliday($id: ID!) {
+    deleteHoliday(id: $id) {
+        ok
+    }
+}
+
+mutation deleteHolidays($ids: [ID]!) {
+    deleteHolidays(ids: $ids) {
+        deletionCount
+    }
+}
+
+mutation updateHolidays($input: [BatchPatchHolidayInput]!) {
+    batchMutation: updateHolidays(input: $input) {
+        items: holidays {
+            id
+            holidayName
+            dateStart
+            dateEnd
+            canEdit
+            canDelete
+        }
+    }
+}
diff --git a/aleksis/core/frontend/routes.js b/aleksis/core/frontend/routes.js
index a1d81600660398926d3ba843be0a5000870f4359..1c3d19d55061869cfa1d740af9160b2c643b0844 100644
--- a/aleksis/core/frontend/routes.js
+++ b/aleksis/core/frontend/routes.js
@@ -363,6 +363,17 @@ const routes = [
           permission: "core.view_schoolterm_rule",
         },
       },
+      {
+        path: "/holidays/",
+        component: () => import("./components/holiday/HolidayInlineList.vue"),
+        name: "core.holidays",
+        meta: {
+          inMenu: true,
+          titleKey: "holidays.menu_title",
+          icon: "$holidays",
+          permission: "core.view_holiday_rule",
+        },
+      },
       {
         path: "/dashboard_widgets/",
         component: () => import("./components/LegacyBaseTemplate.vue"),