diff --git a/src/components/ImageMetadataFields.vue b/src/components/ImageMetadataFields.vue
index 7f5179e319cc6e7e2982813eac76910c5782f188..80ae272ae1c6150f741128cc9c21141868f68d76 100644
--- a/src/components/ImageMetadataFields.vue
+++ b/src/components/ImageMetadataFields.vue
@@ -1,11 +1,12 @@
 <template>
   <div class="flex flex-col flex-1">
-    <form id="payloadFields" class="flex flex-col flex-1">
+    <form :id="formID" class="flex flex-col flex-1">
       <input
         type="text"
         placeholder="Source"
         name="source"
         autocomplete="off"
+        :value="source"
         class="imageInfoFields"
       />
       <input
@@ -13,6 +14,7 @@
         placeholder="Parent"
         name="parent"
         autocomplete="off"
+        :value="parent"
         class="imageInfoFields"
       />
       <textarea
@@ -20,6 +22,7 @@
         placeholder="Commentary"
         name="commentary"
         autocomplete="off"
+        :value="commentary"
         class="imageInfoFields resize-none flex-1"
       />
       <textarea
@@ -27,15 +30,17 @@
         placeholder="Commentary translation"
         name="commentary_translation"
         autocomplete="off"
+        :value="commentaryTranslation"
         class="imageInfoFields resize-none flex-1"
       />
     </form>
     <input
-      id="tagField"
+      :id="tagFieldID"
       type="text"
       placeholder="Tags"
       name="tags"
       autocomplete="off"
+      :value="tags"
       class="imageInfoFields"
     />
   </div>
@@ -46,28 +51,54 @@ import { mapState } from "vuex";
 import paths from "@/assets/js/paths.js";
 
 export default {
+  data: function () {
+    return {
+      formID: "imageInfoFields",
+      tagFieldID: "imageTagField",
+    };
+  },
   props: {
     id: {
       required: true,
     },
+    source: String,
+    parent: String,
+    commentary: String,
+    commentaryTranslation: String,
+    tags: "",
   },
   created() {
     this.$parent.$on(`update-image-info-${this.id}`, this.updateImageMetadata);
+    this.$parent.$on(`update-image-info-${this.id}`, this.imageMetadataUpdated);
   },
   computed: {
     ...mapState(["stateUser"]),
   },
   methods: {
+    imageMetadataUpdated() {
+      this.$parent.$emit(
+        "image-info-updated",
+        this.serializeForm(this.formID),
+        this.sanitizeTagsField(this.tagFieldID)
+      );
+    },
     updateImageMetadata(flake) {
-      this.updateImageInfo(flake, this.serializeForm("payloadFields"));
-      this.updateImageTags(flake, "tagField");
+      this.updateImageInfo(flake, this.serializeForm(this.formID));
+      this.updateImageTags(flake, this.sanitizeTagsField(this.tagFieldID));
     },
-    // Serialize form inputs into JSON object that can be sent to API endpoints
+    // Serialize form inputs into JSON string that can be sent to API endpoints
     serializeForm(formID) {
       return JSON.stringify(
         Object.fromEntries(new FormData(document.getElementById(formID)))
       );
     },
+    sanitizeTagsField(tagFieldID) {
+      // Multiple tags are delimited by a white space
+      return document
+        .getElementById(tagFieldID)
+        .value.split(" ")
+        .filter((element) => element.length > 0);
+    },
     // Send an image update payload including 4 fields:
     // "source", "parent", "commentary", "commentary translation" to paths.ImageField
     async updateImageInfo(flake, imageUpdatePayload) {
@@ -80,18 +111,12 @@ export default {
       };
       await fetch(`/api/image/${flake}`, options);
     },
-    async updateImageTags(flake, tagsInputID) {
-      // Multiple tags are delimited by a white space
-      const tags = document
-        .getElementById(tagsInputID)
-        .value.split(" ")
-        .filter((element) => element.length > 0);
+    async updateImageTags(flake, tagsPayload) {
       const options = {
         method: "PUT",
       };
-
-      for (let i = 0; i < tags.length; i++) {
-        await fetch(paths.ImageTagField(flake, tags[i]), options);
+      for (let i = 0; i < tagsPayload.length; i++) {
+        await fetch(paths.ImageTagField(flake, tagsPayload[i]), options);
       }
     },
   },
diff --git a/src/views/ImagePost.vue b/src/views/ImagePost.vue
index 27ad847338b4f9055e3d165f5c2cae0805a4fa3b..7803a01f0bae516e926eb44caf05870c9386c510 100644
--- a/src/views/ImagePost.vue
+++ b/src/views/ImagePost.vue
@@ -22,12 +22,14 @@
       <div>
         <strong>Options</strong>
         <ul class="pl-2">
+          <li><button @click="editToggle = !editToggle">Edit</button></li>
           <li><button @click="removeImage">Remove</button></li>
         </ul>
       </div>
     </section>
     <section class="flex-auto ml-12">
       <img :src="`/api/image/${flake}/file`" alt="" class="max-w-4xl" />
+      <!-- Image's commentary and translated commentary -->
       <div
         v-if="imageInfo.commentary || imageInfo.commentary_translation"
         class="bg-gray-200 bg-opacity-60 p-4 m-2"
@@ -55,6 +57,26 @@
           }}
         </div>
       </div>
+      <!-- Metadata fields -->
+      <div v-if="editToggle">
+        <strong>Edit image metadata</strong>
+        <ImageMetadataFields
+          :source="imageInfo.source"
+          :parent="imageInfo.parent"
+          :commentary="imageInfo.commentary"
+          :commentaryTranslation="imageInfo.commentary_translation"
+          :tags="imageTags === null ? '' : imageTags.join(' ')"
+          id="0"
+        ></ImageMetadataFields>
+        <button
+          @click="
+            $emit('update-image-info-0', flake);
+            editToggle = false;
+          "
+        >
+          Submit
+        </button>
+      </div>
     </section>
   </div>
 </template>
@@ -62,11 +84,16 @@
 <script>
 import { mapState } from "vuex";
 import paths from "@/assets/js/paths.js";
+import ImageMetadataFields from "@/components/ImageMetadataFields.vue";
 
 export default {
+  components: {
+    ImageMetadataFields,
+  },
   data: function () {
     return {
       imageTags: Array,
+      editToggle: false,
       originalComment: true,
       imageInfo: Object,
       flake: this.$route.params.flake,
@@ -105,8 +132,12 @@ export default {
     },
   },
   async created() {
-    this.imageTags = await this.getImageTags();
     this.imageInfo = await this.getImageInfo();
+    this.imageTags = await this.getImageTags();
+    this.$on("image-info-updated", (imageInfoFields, imageTagField) => {
+      this.imageInfo = JSON.parse(imageInfoFields);
+      this.imageTags = imageTagField;
+    });
   },
 };
 </script>
\ No newline at end of file