Load and save a DOCX
Load a DOCX from your application and save the edited file back to your backend.
Continue with /sample.docx from the Quickstart. Replace the local file with a backend round trip:
- Fetch the DOCX from your API as a
Blob. - Open and edit the
Blobin SuperDoc. - Export the edited DOCX as a new
Bloband send it back to your API.
SuperDoc handles the DOCX in the browser. Your application owns the API and storage.
1. Add a document endpoint
The examples use /api/documents/sample. This is an application route, not a SuperDoc route.
| Request | Your endpoint must |
|---|---|
GET | Return the current DOCX bytes |
PUT | Store the request body and return a success status after the write finishes |
The Quickstart Vite project does not create this endpoint. Connect the example to your application API, or add a local endpoint with this contract.
The endpoint can read from a database or an object store such as Amazon S3. The browser code stays the same. Keep storage credentials and access checks in your backend.
2. Add a save action
For Vanilla, replace the Quickstart controls with a save action and status:
<button id="save-docx" type="button" disabled>Save DOCX</button>
<output id="document-status">Opening…</output>
<div id="editor"></div>The React example below renders its own controls.
3. Load and save the document
The examples show the complete storage flow. Add any user, mode, or viewing options you chose on the previous pages to the Editor configuration.
import { DOCX, SuperDoc } from 'superdoc';
import 'superdoc/style.css';
function requireElement<ElementType extends Element>(selector: string) {
const element = document.querySelector<ElementType>(selector);
if (!element) throw new Error(`${selector} not found.`);
return element;
}
const saveButton = requireElement<HTMLButtonElement>('#save-docx');
const status = requireElement<HTMLOutputElement>('#document-status');
const endpoint = '/api/documents/sample';
let isReady = false;
let editRevision = 0;
let superdoc: SuperDoc | undefined;
function showOpenError(error: unknown) {
console.error('Could not open the document.', error);
if (isReady) return;
status.value = 'Could not open the document. Reload to try again.';
saveButton.disabled = true;
}
try {
const response = await fetch(endpoint);
if (!response.ok) throw new Error(`Could not load the document: ${response.status}`);
const docx = new Blob([await response.arrayBuffer()], { type: DOCX });
superdoc = new SuperDoc({
selector: '#editor',
document: docx,
onReady: () => {
isReady = true;
status.value = 'Ready';
saveButton.disabled = false;
},
onEditorUpdate: () => {
editRevision += 1;
status.value = 'Unsaved changes';
},
onContentError: ({ error }) => showOpenError(error),
onException: ({ error }) => showOpenError(error),
});
} catch (error) {
showOpenError(error);
}
saveButton.addEventListener('click', async () => {
if (!superdoc || !isReady) return;
const savedRevision = editRevision;
saveButton.disabled = true;
status.value = 'Saving…';
try {
const editedDocx = await superdoc.export({
exportType: ['docx'],
triggerDownload: false,
});
if (!(editedDocx instanceof Blob)) throw new Error('Expected one DOCX file.');
const saveResponse = await fetch(endpoint, {
method: 'PUT',
headers: { 'content-type': DOCX },
body: editedDocx,
});
if (!saveResponse.ok) throw new Error(`Could not save the document: ${saveResponse.status}`);
status.value = editRevision === savedRevision ? 'Saved' : 'Unsaved changes';
} catch (error) {
status.value = 'Save failed. Try again.';
console.error('The document was not saved.', error);
} finally {
saveButton.disabled = false;
}
});
window.addEventListener('beforeunload', () => superdoc?.destroy());
Both examples:
- fetch the DOCX before mounting the Editor;
- enable saving after
onReady; - call
export({ triggerDownload: false })to receive the editedBlob; - show Saved only after the
PUTsucceeds. Edits made during that request remain unsaved.
Use another source or destination
| Task | Use |
|---|---|
| Open a public or signed URL | document: url |
| Open a file selected by a user | document: file |
| Switch the mounted Editor | await superdoc.replaceFile(nextDocx) |
| Download instead of saving | await superdoc.export({ exportedName: 'sample-edited' }) |
A URL from another origin must allow the browser request through CORS. Fetch the file yourself and pass a Blob when
the request needs custom headers.
Verify the round trip
Change the effective date from September 1, 2026 to October 1, 2026. Select Save DOCX, then reload the page. The
new date should still be present. If the PUT fails, the status should show Save failed and the stored file should
remain unchanged.
Continue from here
- Version history keeps earlier saves so users can restore them.
- Export options changes the filename, comment policy, or related files.
- If your content starts as HTML or Markdown, see rich content and output projections. These APIs do not open either format as a DOCX file.