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:

  1. Fetch the DOCX from your API as a Blob.
  2. Open and edit the Blob in SuperDoc.
  3. Export the edited DOCX as a new Blob and 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.

RequestYour endpoint must
GETReturn the current DOCX bytes
PUTStore 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.

src/main.ts
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 edited Blob;
  • show Saved only after the PUT succeeds. Edits made during that request remain unsaved.

Use another source or destination

TaskUse
Open a public or signed URLdocument: url
Open a file selected by a userdocument: file
Switch the mounted Editorawait superdoc.replaceFile(nextDocx)
Download instead of savingawait 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

On this page