In the example below, uploading an image as base64 works fine for me. With a few minor changes, you can upload the image to the server and have it added dynamically.
<template>
<div>
<editor-content :editor="editor" />
<input
type="file"
id="file-upload-input"
ref="fileInput"
@change="onFileChange"
accept="image/png,image/jpg,image/jpeg,image/gif,image/webp"
hidden
/>
<button @click="triggerFileUpload">Upload Image</button>
</div>
</template>
<script>
import { ref, onMounted, onBeforeUnmount } from "vue";
import { EditorContent, useEditor } from "@tiptap/vue-3";
import StarterKit from "@tiptap/starter-kit";
import Image from "@tiptap/extension-image";
export default {
name: "TiptapImageUpload",
components: { EditorContent },
setup() {
const editor = useEditor({
extensions: [
StarterKit,
Image.extend({
addOptions() {
return {
...this.parent?.(),
inline: false,
allowBase64: true,
};
},
}),
],
content: "<p>Click the button below to upload an image!</p>",
});
const onFileChange = async (event) => {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = () => {
const base64 = reader.result;
editor
.chain()
.focus()
.setImage({ src: base64 })
.run();
};
reader.readAsDataURL(file);
}
event.target.value = ""; // Reset the input
};
const triggerFileUpload = () => {
document.getElementById("file-upload-input").click();
};
onMounted(() => {
console.log("Editor mounted");
});
onBeforeUnmount(() => {
editor?.destroy();
});
return {
editor,
triggerFileUpload,
onFileChange,
};
},
};
</script>
<style>
/* Basic styling */
button {
margin-top: 10px;
padding: 8px 16px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
</style>