SuperDoc works with Nuxt 4+ as a client-side Vue component. Set ssr: false in your Nuxt config — SuperDoc manipulates the DOM directly and doesn’t run server-side.
Install
export default defineNuxtConfig({
ssr: false,
css: ['superdoc/style.css'],
compatibilityDate: '2025-07-15',
})
ssr: false is required. SuperDoc renders documents in the browser using DOM APIs that aren’t available server-side.
Basic setup
Nuxt auto-imports Vue’s ref, watch, and lifecycle hooks — no manual imports needed.
<script setup lang="ts">
import { SuperDoc } from 'superdoc';
const container = ref<HTMLDivElement | null>(null);
const file = ref<File | null>(null);
let superdoc: SuperDoc | null = null;
const handleFile = (e: Event) => {
const input = e.target as HTMLInputElement;
if (input.files?.[0]) file.value = input.files[0];
};
const initEditor = () => {
if (!container.value || !file.value) return;
superdoc?.destroy();
superdoc = new SuperDoc({
selector: container.value,
document: file.value,
});
};
watch(file, initEditor);
onBeforeUnmount(() => superdoc?.destroy());
</script>
<template>
<div>
<div style="padding: 1rem; background: #f5f5f5">
<input type="file" accept=".docx" @change="handleFile" />
</div>
<div ref="container" style="height: calc(100vh - 60px)" />
</div>
</template>
Full component
Build a reusable DOCX editor component with controls:
app/components/DocEditor.vue
<script setup lang="ts">
import { SuperDoc } from 'superdoc';
const props = defineProps<{
document: string | File | Blob;
}>();
const editor = ref<HTMLDivElement | null>(null);
let superdoc: SuperDoc | null = null;
onMounted(() => {
if (!editor.value) return;
superdoc = new SuperDoc({
selector: editor.value,
document: props.document,
documentMode: 'editing',
});
});
onBeforeUnmount(() => superdoc?.destroy());
const setMode = (mode: 'editing' | 'suggesting' | 'viewing') => {
superdoc?.setDocumentMode(mode);
};
const exportFinal = async () => {
await superdoc?.export({ isFinalDoc: true });
};
</script>
<template>
<div>
<div class="controls">
<button @click="setMode('editing')">Edit</button>
<button @click="setMode('suggesting')">Review</button>
<button @click="setMode('viewing')">View</button>
<button @click="exportFinal">Export Final</button>
</div>
<div ref="editor" class="editor-container" />
</div>
</template>
<style scoped>
.editor-container {
height: 700px;
border: 1px solid #e2e8f0;
}
.controls {
padding: 1rem;
display: flex;
gap: 0.5rem;
}
</style>
Then use it in a page:
<script setup lang="ts">
const file = ref<File | null>(null);
const handleFile = (e: Event) => {
const input = e.target as HTMLInputElement;
if (input.files?.[0]) file.value = input.files[0];
};
</script>
<template>
<div>
<input type="file" accept=".docx" @change="handleFile" />
<DocEditor v-if="file" :document="file" />
</div>
</template>
Next steps