End-to-end walkthrough: import, edit, export
This guide walks you from an empty project to a working DOCX import and export, end to end. We'll set up the editor with ConvertKit, wire up a file input that sends DOCX uploads through the Conversion service, and round-trip the document back out to DOCX. Step 6 shows how to layer the Pages extension on top if you want a paginated editor.
Prerequisites
- A Tiptap account with a Pro plan or trial.
- Access to Tiptap's private npm registry.
- Your App ID and secret key from the Convert settings page.
1. Install the Conversion stack
npm install @tiptap-pro/extension-convert-kit \
@tiptap-pro/extension-import-docx \
@tiptap-pro/extension-export-docxWhy ConvertKit, always
ConvertKit is the canonical editor kit for Conversion. It registers the DOCX-aware schema —
paragraph spacing, image crop, table cell formatting — that the import service produces and the
export service consumes. Don't substitute StarterKit; you'll lose those attributes on
round-trip.
2. Set up the editor with ConvertKit
import { Editor } from '@tiptap/core'
import { ConvertKit } from '@tiptap-pro/extension-convert-kit'
import { ImportDocx } from '@tiptap-pro/extension-import-docx'
import { ExportDocx } from '@tiptap-pro/extension-export-docx'
const editor = new Editor({
element: document.querySelector('#editor'),
extensions: [
ConvertKit,
ImportDocx.configure({
appId: 'YOUR_APP_ID',
token: 'YOUR_JWT', // generate this server-side
}),
ExportDocx.configure({
onCompleteExport: (result) => {
// Step 5 fills this in
},
}),
],
})Generating the JWT
Always generate JWTs on your server. Never embed the secret key in browser code. See the Conversion install guide for details on token shape.
3. Wire up DOCX import
Add a file input to the page and pass the selected file to the editor's import command:
<input type="file" id="docx-input" accept=".docx" />const input = document.querySelector<HTMLInputElement>('#docx-input')!
input.addEventListener('change', () => {
const file = input.files?.[0]
if (!file) return
editor.chain().focus().importDocx({ file }).run()
})That's the full path. The conversion service receives the DOCX, returns Tiptap JSON, and the editor renders it using ConvertKit's schema.
4. Handle the import result yourself
The default import replaces the editor content. To validate, transform, or surface errors, pass an onImport callback:
editor
.chain()
.focus()
.importDocx({
file,
onImport(context) {
if (context.error) {
console.error('Import failed:', context.error)
return
}
// Inspect or transform `context.content` here. To use it as-is, call setEditorContent().
// To replace with your own transformation, use editor.commands.setContent().
context.setEditorContent()
},
})
.run()The content object is plain Tiptap JSON. Logging it is the fastest way to see what the converter actually produced — useful when a feature renders unexpectedly.
5. Configure DOCX export
Fill in the onCompleteExport callback with a download trigger:
ExportDocx.configure({
onCompleteExport: (result) => {
const blob = new Blob([result], {
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
})
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = 'document.docx'
a.click()
URL.revokeObjectURL(url)
},
exportType: 'blob', // default; explicit here for clarity
})Trigger an export from a button:
document.querySelector('#export')!.addEventListener('click', () => {
editor.commands.exportDocx()
})DOCX export is client-side: no JWT, no App ID, no API call. The conversion happens in the extension itself.
Round-trip is not byte-identical
A few features (subscript/superscript marks, paragraph line-height, floating tables) round-trip imperfectly today. See the feature support matrix for the full list. Don't rely on a DOCX → edit → DOCX cycle producing the original file byte-for-byte.
6. (Optional) Add Pages for paginated rendering
If you want the editor to look like a real document — page boundaries, headers and footers, page format — add the Pages extension and PagesTableKit on top of the same setup:
npm install @tiptap-pro/extension-pages-tablekit @tiptap-pro/extension-pagesimport { ConvertKit } from '@tiptap-pro/extension-convert-kit'
import { TableKit } from '@tiptap-pro/extension-pages-tablekit'
import { Pages } from '@tiptap-pro/extension-pages'
import { ImportDocx } from '@tiptap-pro/extension-import-docx'
import { ExportDocx } from '@tiptap-pro/extension-export-docx'
const editor = new Editor({
extensions: [
ConvertKit.configure({ table: false }), // disable ConvertKit's tables
TableKit, // pagination-safe tables instead
Pages.configure({
pageFormat: 'A4',
header: 'My document',
footer: 'Page {page} of {total}',
}),
ImportDocx.configure({ appId: 'YOUR_APP_ID', token: 'YOUR_JWT' }),
ExportDocx.configure({ onCompleteExport: /* ... */ }),
],
})The diff from Step 2:
- Disable ConvertKit's tables (
{ table: false }); ConvertKit's bundled tables are not pagination-safe. - Add
TableKitfromextension-pages-tablekit. - Add
Pages.configure({...}).
Imported documents now render with their headers, footers, and page formats applied. The export path is unchanged — editor.commands.exportDocx() still works, and the exported DOCX preserves headers and footers from the Pages overlay.
Important Pages limit
Read the Pages limitations page before shipping. Tables and other non-splittable blocks taller than the page can put the layout into an infinite loop.
What to expect
- Imports always go through the service. Even a small DOCX hits the Conversion service to be parsed. The service requires
appIdand a JWT. - Exports are local. DOCX export runs in the browser; no auth, no network call.
- Round-trip drift is real. Plan for the features in the matrix that don't round-trip (subscript marks, line-height) — either avoid those features in your editor schema or accept the drift.
What not to expect
- OCR or scanned-PDF processing. Conversion handles structured documents, not bitmap-of-a-page input.
- Real-time collaboration in this setup. Pair with the Tiptap Collaboration product if you need multi-user editing — see Adding collaboration to Pages when combining with Pages.
- Asynchronous job control. The service responds synchronously to each request. Plan timeouts on your side for very large documents.
Next steps
- ConvertKit reference — the schema you registered
- Import DOCX — full API of the import extension
- Export DOCX — full API of the export extension
- Feature support matrix — what round-trips and what doesn't
- Pages overview — paginated editor layout
- Debugging — diagnose failed imports, schema mismatches, and HTTP errors