diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.html b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.html
index 8fd44e66ab..d300cde333 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.html
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.html
@@ -17,7 +17,7 @@
 
         <div wicket:id="grading_template_component_panel"></div>
 
-        <div class="position-sticky bottom-0 bg-white p-3 border line-length-limit">
+        <div wicket:id="button_container" class="position-sticky bottom-0 bg-white p-3 border line-length-limit">
             <button type="submit" class="btn btn-primary">Create</button>
         </div>
     </form>
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.java
index c14d4925db..0338617189 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.java
@@ -3,6 +3,7 @@ package se.su.dsv.scipro.admin.pages.grading;
 import jakarta.inject.Inject;
 import org.apache.wicket.RestartResponseException;
 import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.form.LambdaChoiceRenderer;
 import org.apache.wicket.markup.html.panel.FeedbackPanel;
@@ -29,6 +30,7 @@ public class AdminGradingTemplateCreationPage extends AbstractAdminProjectPage i
 
     private final IModel<ProjectType> projectTypeModel;
     private EditingGradingTemplate editingGradingTemplateModel;
+    private final WebMarkupContainer buttonContainer;
 
     public AdminGradingTemplateCreationPage() {
         projectTypeModel = new DetachableServiceModel<>(projectTypeService);
@@ -57,6 +59,11 @@ public class AdminGradingTemplateCreationPage extends AbstractAdminProjectPage i
         form.setOutputMarkupId(true);
         add(form);
 
+        buttonContainer = new WebMarkupContainer("button_container");
+        buttonContainer.setOutputMarkupPlaceholderTag(true);
+        buttonContainer.setVisible(false);
+        form.add(buttonContainer);
+
         form.add(new AjaxDropDownChoice<>(
                 "project_type",
                 projectTypeModel,
@@ -64,7 +71,8 @@ public class AdminGradingTemplateCreationPage extends AbstractAdminProjectPage i
                 new LambdaChoiceRenderer<>(ProjectType::getName, ProjectType::getId)) {
             @Override
             public void onNewSelection(AjaxRequestTarget target, ProjectType objectSelected) {
-                target.add(form);
+                buttonContainer.setVisible(true);
+                target.add(form, buttonContainer);
             }
         });
 
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.html b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.html
index 9e28766880..cd7a505d25 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.html
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.html
@@ -3,10 +3,18 @@
 <body>
 <wicket:extend>
     <div wicket:id="feedback"></div>
+    <div class="mb-3 lead">
+        <wicket:message key="project_type_name_editing">
+            <span wicket:id="project_type_name"></span>
+        </wicket:message>
+    </div>
     <form wicket:id="form">
         <div wicket:id="editing" class="mb-3"></div>
-        <div class="position-sticky bottom-0 bg-white p-3 border line-length-limit">
+        <div class="position-sticky bottom-0 bg-white p-3 border line-length-limit hstack">
             <button type="submit" class="btn btn-primary">Save</button>
+            <span wicket:id="unsaved_changes_alert" class="text-danger flex-grow-1 text-center" role="alert">
+                <wicket:message key="unsaved_changes"/>
+            </span>
         </div>
     </form>
 </wicket:extend>
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java
index da4a0b42a7..d2ad546e0f 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java
@@ -2,9 +2,13 @@ package se.su.dsv.scipro.admin.pages.grading;
 
 import jakarta.inject.Inject;
 import org.apache.wicket.RestartResponseException;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.panel.FeedbackPanel;
-import org.apache.wicket.model.Model;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 import se.su.dsv.scipro.admin.pages.AbstractAdminProjectPage;
 import se.su.dsv.scipro.grading.GradingReportTemplateService;
@@ -12,9 +16,10 @@ import se.su.dsv.scipro.grading.GradingReportTemplateUpdate;
 import se.su.dsv.scipro.grading.LocalizedString;
 import se.su.dsv.scipro.report.DuplicateDateException;
 import se.su.dsv.scipro.report.GradingReportTemplate;
-import se.su.dsv.scipro.report.ValidDateMustBeInTheFutureException;
 import se.su.dsv.scipro.report.NoSuchTemplateException;
 import se.su.dsv.scipro.report.TemplateLockedException;
+import se.su.dsv.scipro.report.ValidDateMustBeInTheFutureException;
+import se.su.dsv.scipro.system.ProjectType;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -25,6 +30,8 @@ public class AdminGradingTemplateEditPage extends AbstractAdminProjectPage imple
             0,
             new LocalizedString("", ""));
 
+    private final WebMarkupContainer unsavedChangesAlert;
+
     @Inject
     GradingReportTemplateService gradingReportTemplateService;
 
@@ -38,6 +45,8 @@ public class AdminGradingTemplateEditPage extends AbstractAdminProjectPage imple
         editingGradingTemplate = new EditingGradingTemplate(template);
 
         add(new FeedbackPanel("feedback"));
+        IModel<GradingReportTemplate> model = LoadableDetachableModel.of(() -> gradingReportTemplateService.getTemplate(id));
+        add(new Label("project_type_name", model.map(GradingReportTemplate::getProjectType).map(ProjectType::getName)));
 
         Form<EditingGradingTemplate> form = new Form<>("form") {
             @Override
@@ -47,7 +56,8 @@ public class AdminGradingTemplateEditPage extends AbstractAdminProjectPage imple
                     GradingReportTemplateUpdate update = toUpdate(
                             editingGradingTemplate);
 
-                    gradingReportTemplateService.update(id, update);
+                    GradingReportTemplate newTemplate = gradingReportTemplateService.update(id, update);
+                    editingGradingTemplate = new EditingGradingTemplate(newTemplate);
                     success(getString("template_updated"));
                 } catch (ValidDateMustBeInTheFutureException e) {
                     error(getString("valid_from_must_be_in_the_future", () -> e));
@@ -61,7 +71,23 @@ public class AdminGradingTemplateEditPage extends AbstractAdminProjectPage imple
             }
         };
 
-        form.add(new EditingGradingTemplateComponentPanel("editing", Model.of(editingGradingTemplate)));
+        unsavedChangesAlert = new WebMarkupContainer("unsaved_changes_alert") {
+            @Override
+            protected void onConfigure() {
+                super.onConfigure();
+                setVisible(editingGradingTemplate.hasChanges());
+            }
+        };
+        form.add(unsavedChangesAlert);
+        unsavedChangesAlert.setOutputMarkupPlaceholderTag(true);
+
+        form.add(new EditingGradingTemplateComponentPanel("editing", () -> editingGradingTemplate) {
+            @Override
+            protected void onTemplateChanged(AjaxRequestTarget target) {
+                super.onTemplateChanged(target);
+                target.add(unsavedChangesAlert);
+            }
+        });
         add(form);
     }
 
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java
index 7e4e935ad5..a56af9d4eb 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java
@@ -8,12 +8,15 @@ import java.io.Serializable;
 import java.time.LocalDate;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 class EditingGradingTemplate implements Serializable {
+    private EditingGradingTemplate original;
     private String note;
     private LocalDate validFrom;
     private List<Criteria> criteria;
     private GradeLimits gradeLimits;
+    private String projectType;
 
     public EditingGradingTemplate() {
         this.gradeLimits = new GradeLimits();
@@ -21,6 +24,16 @@ class EditingGradingTemplate implements Serializable {
     }
 
     EditingGradingTemplate(GradingReportTemplate template) {
+        this(template, null);
+        this.original = new EditingGradingTemplate(template, null);
+    }
+
+    /**
+     * Private constructor for creating a new instance of EditingGradingTemplate
+     * to be able to track changes made.
+     * @param doNotCreateOriginal Only exists to differentiate the signature from the public constructor
+     */
+    private EditingGradingTemplate(GradingReportTemplate template, @SuppressWarnings("unused") Void doNotCreateOriginal) {
         this.note = template.getNote();
         this.validFrom = template.getValidFrom();
         this.gradeLimits = new GradeLimits(template);
@@ -29,6 +42,7 @@ class EditingGradingTemplate implements Serializable {
             Criteria editingCriteria = new Criteria(criteria);
             this.criteria.add(editingCriteria);
         }
+        this.projectType = template.getProjectType().getName();
     }
 
     public String getNote() {
@@ -61,8 +75,34 @@ class EditingGradingTemplate implements Serializable {
                 .sum();
     }
 
+    public Boolean hasChanges() {
+        return !Objects.equals(original, this);
+    }
+
     public void addCriteria() {
-        this.criteria.add(new Criteria());
+        Criteria newCriteria = new Criteria();
+        newCriteria.points.add(newCriteria.new Point());
+        this.criteria.add(newCriteria);
+
+    }
+
+    public String getProjectType() {
+        return projectType;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return o instanceof EditingGradingTemplate that
+                && Objects.equals(note, that.note)
+                && Objects.equals(validFrom, that.validFrom)
+                && Objects.equals(criteria, that.criteria)
+                && Objects.equals(gradeLimits, that.gradeLimits)
+                && Objects.equals(projectType, that.projectType);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(note, validFrom, criteria, gradeLimits);
     }
 
     class Criteria implements Serializable {
@@ -79,14 +119,14 @@ class EditingGradingTemplate implements Serializable {
         private List<Point> points = new ArrayList<>();
         private Flag flag;
         private Type type = Type.PROJECT;
-        private int pointsRequiredToPass;
+        private int pointsRequiredToPass = 1;
 
         Criteria(GradingCriterionTemplate criteria) {
             this.titleSv = criteria.getTitle();
             this.titleEn = criteria.getTitleEn();
             this.pointsRequiredToPass = criteria.getPointsRequiredToPass();
             for (var point : criteria.getGradingCriterionPointTemplates()) {
-                if (point.getPoint() == 0) continue;
+                if (point.getPoint() == 0) continue; // This is to hide zero point requirements that never have any text
                 Point editingPoint = new Point(point);
                 this.points.add(editingPoint);
             }
@@ -150,6 +190,22 @@ class EditingGradingTemplate implements Serializable {
             this.pointsRequiredToPass = pointsRequiredToPass;
         }
 
+        @Override
+        public boolean equals(Object o) {
+            return o instanceof Criteria criterion
+                    && pointsRequiredToPass == criterion.pointsRequiredToPass
+                    && Objects.equals(titleSv, criterion.titleSv)
+                    && Objects.equals(titleEn, criterion.titleEn)
+                    && Objects.equals(points, criterion.points)
+                    && flag == criterion.flag
+                    && type == criterion.type;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(titleSv, titleEn, points, flag, type, pointsRequiredToPass);
+        }
+
         class Point implements Serializable {
             private String requirementEn;
             private String requirementSv;
@@ -179,6 +235,18 @@ class EditingGradingTemplate implements Serializable {
             public void setRequirementSv(String requirementSv) {
                 this.requirementSv = requirementSv;
             }
+
+            @Override
+            public boolean equals(Object o) {
+                return o instanceof Point point
+                        && Objects.equals(requirementEn, point.requirementEn)
+                        && Objects.equals(requirementSv, point.requirementSv);
+            }
+
+            @Override
+            public int hashCode() {
+                return Objects.hash(requirementEn, requirementSv);
+            }
         }
     }
 }
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
index fb6b0af006..6a59cfa2f5 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
@@ -22,6 +22,9 @@ import java.time.LocalDate;
 import java.util.List;
 
 class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTemplate> {
+
+    private final Label maxPointsAvailable;
+
     EditingGradingTemplateComponentPanel(
             String id,
             IModel<EditingGradingTemplate> editingGradingTemplateModel)
@@ -36,7 +39,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                         EditingGradingTemplate::setValidFrom),
                 LocalDate.class);
         validFromField.add(new BootstrapDatePicker());
-        validFromField.add(new AutoSave());
+        validFromField.add(new AutoSave("changeDate"));
         add(validFromField);
 
         add(new TextArea<>("note", LambdaModel.of(
@@ -50,7 +53,10 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
 
         add(new GradeLimitsPanel("grade_limits", editingGradingTemplateModel.map(EditingGradingTemplate::getGradeLimits)));
 
-        add(new Label("max_points_available", editingGradingTemplateModel.map(EditingGradingTemplate::getMaxPointsAvailable)));
+        maxPointsAvailable = new Label("max_points_available", editingGradingTemplateModel.map(EditingGradingTemplate::getMaxPointsAvailable));
+        maxPointsAvailable.setOutputMarkupId(true);
+        add(maxPointsAvailable);
+
 
         add(new ListView<>("criteria", editingGradingTemplateModel.map(EditingGradingTemplate::getCriteria)) {
             {
@@ -64,6 +70,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                     public void onClick(AjaxRequestTarget target) {
                         editingGradingTemplateModel.getObject().getCriteria().remove(item.getModelObject());
                         target.add(EditingGradingTemplateComponentPanel.this);
+                        onTemplateChanged(target);
                     }
                 });
                 item.add(new CriteriaEditingPanel("criteria", item.getModel()));
@@ -75,6 +82,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
             public void onClick(AjaxRequestTarget target) {
                 editingGradingTemplateModel.getObject().addCriteria();
                 target.add(EditingGradingTemplateComponentPanel.this);
+                onTemplateChanged(target);
             }
         });
     }
@@ -117,6 +125,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                         EditingGradingTemplate.Criteria.Type objectSelected)
                 {
                     // auto save
+                    onTemplateChanged(target);
                 }
             };
             typeChoice.setRequired(true);
@@ -149,6 +158,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                         EditingGradingTemplate.Criteria.Flag objectSelected)
                 {
                     // auto save
+                    onTemplateChanged(target);
                 }
             };
             flagChoice.setNullValid(true);
@@ -176,6 +186,8 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                     EditingGradingTemplate.Criteria.Point newPoint = criteria.new Point();
                     criteria.getPoints().add(newPoint);
                     target.add(CriteriaEditingPanel.this);
+                    target.add(maxPointsAvailable);
+                    onTemplateChanged(target);
                 }
             });
         }
@@ -210,13 +222,14 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                         EditingGradingTemplate.Criteria criteria = CriteriaEditingPanel.this.getModelObject();
                         criteria.getPoints().remove(model.getObject());
                         target.add(CriteriaEditingPanel.this);
+                        onTemplateChanged(target);
                     }
                 });
             }
         }
     }
 
-    private static class GradeLimitsPanel extends GenericWebMarkupContainer<GradeLimits> {
+    private class GradeLimitsPanel extends GenericWebMarkupContainer<GradeLimits> {
         public GradeLimitsPanel(String id, IModel<GradeLimits> model) {
             super(id, model);
 
@@ -248,6 +261,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                     GradeLimits gradeLimits = GradeLimitsPanel.this.getModelObject();
                     gradeLimits.addNewLimit();
                     target.add(GradeLimitsPanel.this);
+                    onTemplateChanged(target);
                 }
             });
         }
@@ -278,20 +292,30 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                         GradeLimits gradeLimits = GradeLimitsPanel.this.getModelObject();
                         gradeLimits.getGradeLimits().remove(model.getObject());
                         target.add(GradeLimitsPanel.this);
+                        onTemplateChanged(target);
                     }
                 });
             }
         }
     }
 
-    private static class AutoSave extends AjaxFormComponentUpdatingBehavior {
+    private class AutoSave extends AjaxFormComponentUpdatingBehavior {
         public AutoSave() {
             super("input");
         }
 
+        public AutoSave(String event) {
+            super(event);
+        }
+
         @Override
         protected void onUpdate(AjaxRequestTarget target) {
             // just trigger the ajax call is enough to update the model object
+            onTemplateChanged(target);
         }
     }
+
+    protected void onTemplateChanged(AjaxRequestTarget target) {
+        // do nothing
+    }
 }
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/GradeLimits.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/GradeLimits.java
index 29bd5877d2..dae5812f7a 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/GradeLimits.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/GradeLimits.java
@@ -5,6 +5,7 @@ import se.su.dsv.scipro.report.GradingReportTemplate;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 class GradeLimits implements Serializable {
     private List<GradeLimit> gradeLimits;
@@ -41,6 +42,19 @@ class GradeLimits implements Serializable {
         return gradeLimits;
     }
 
+    @Override
+    public boolean equals(Object o) {
+
+        return o instanceof GradeLimits that
+                && Objects.equals(gradeLimits, that.gradeLimits)
+                && Objects.equals(failingGrade, that.failingGrade);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(gradeLimits, failingGrade);
+    }
+
     class GradeLimit implements Serializable {
         private String grade;
         private int lowerLimit;
@@ -60,5 +74,17 @@ class GradeLimits implements Serializable {
         public void setLowerLimit(int lowerLimit) {
             this.lowerLimit = lowerLimit;
         }
+
+        @Override
+        public boolean equals(Object o) {
+            return o instanceof GradeLimit that
+                    && lowerLimit == that.lowerLimit
+                    && Objects.equals(grade, that.grade);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(grade, lowerLimit);
+        }
     }
 }
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/wicket-package.utf8.properties b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/wicket-package.utf8.properties
index f761f20e4e..defb43b968 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/wicket-package.utf8.properties
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/wicket-package.utf8.properties
@@ -3,3 +3,5 @@ valid_from_must_be_in_the_future=The templates valid date must be in the future.
 another_template_exists_for_the_given_date_date=There is already another ${projectType.name} template that becomes valid at ${validFrom}, please pick another date.
 template_is_locked=You can not edit templates that have become current. The template you are trying to edit became current at ${validFrom}.
 template_created=New template for ${name} created.
+unsaved_changes=The grading template has been changed, unsaved changes will be lost if you do not save.
+project_type_name_editing=You are editing a ${project_type_name} grading template.