Import .docx in your editor
Converting .docx files to Tiptap JSON is simple with the @tiptap-pro/extension-import-docx editor extension,
which integrates directly into your Tiptap Editor.
If you need to import .docx content outside the Editor, use the REST API.
Install the DOCX Import extension
The Conversion extensions are published in Tiptap’s private npm registry. Integrate the extensions by following the private registry guide.
Install the Tiptap Import extension package:
npm i @tiptap-pro/extension-import-docxEnsure your editor includes all necessary Tiptap extensions to handle content from DOCX. For example, include the Image extension for inline images, and the Table extension for tables.
Required extensions
In order to fully map DOCX content (e.g. images, tables, styled text) onto Tiptap’s schema, you must include the relevant Tiptap extensions. Without these extensions, certain DOCX elements may not be recognized or properly rendered by the editor.
import StarterKit from '@tiptap/starter-kit'
import Color from '@tiptap/extension-color'
import FontFamily from '@tiptap/extension-font-family'
import Highlight from '@tiptap/extension-highlight'
import { Image } from '@tiptap/extension-image'
import Paragraph from '@tiptap/extension-paragraph'
import { TableKit } from '@tiptap/extension-table'
import TextAlign from '@tiptap/extension-text-align'
import { TextStyle } from '@tiptap/extension-text-style'Configure
Add the Import extension to your editor setup.
// Import the Import extension
import { Import } from '@tiptap-pro/extension-import-docx'
const editor = new Editor({
extensions: [
// Other extensions ...
Import.configure({
appId: 'your-app-id', // Your Convert App ID (see Tiptap Cloud settings)
token: 'your-jwt', // JWT for authentication (see Authentication documentation)
imageUploadCallbackUrl: 'https://your-image-upload-endpoint.com', // Your upload images endpoint
})
// Other extensions ...
],
// Other editor settings ...
})| Property | Description |
|---|---|
appId | The ID of your Tiptap Convert app (find this in your Tiptap account's conversion settings) |
token | A JWT authentication token generated by your server for the Convert service. (See the Authentication guide for details on obtaining and using these credentials.) |
imageUploadCallbackUrl | An endpoint to upload images found in the DOCX. The conversion service will send each embedded image to this URL and use the returned URL in the content. And any images that cannot be handled will be stripped out. |
verbose | A string | number configuration property to help you control the level of diagnostic output during the import process. This is especially useful for debugging or for getting more insight into what happens during conversion. See more at Verbose output |
Import a DOCX file
Once the extension is configured, you can import a DOCX file selected by the user.
Basic import
The simplest approach is to pass the file directly to the import command. Here it replaces the current editor content with the converted content and focuses the editor:
editor.chain().focus().import({ file }).run()In most cases, this one-liner is all you need to let users import .docx files. The extension handles sending the file to the conversion endpoint, retrieving the converted Tiptap JSON, and inserting it into the editor.
Import handling
In order to have more control after the import process have finished, you would use the onImport callback to handle the conversion result. This callback provides the converted content, any errors that occurred, and a function called setEditorContent to insert the content from context.content into the editor. If you don't provide an onImport callback, the extension will automatically insert the content into the editor but you won't be able to handle anything else like errors or loading states.
editor
.chain()
.import({
file,
onImport(context) {
const { setEditorContent, content, error } = context
// Add error handling
if (error) {
showErrorToast({ message: error.message })
}
// You could also modify the content before inserting it
content.doc.content.push({ type: 'paragraph', content: [{ type: 'text', text: 'Hello!' }] })
// You can change the loading state of your application for example
isLoading = false
// Perform the insertion in the editor
editor.commands.setEditorContent(content)
},
})
.focus()
.run()Operations that we have controlled in the example above:
| Operation | Description |
|---|---|
| Error Handling | If the conversion fails, you can display a toast or log the error. |
| Content Modification | You can insert extra nodes, remove certain nodes, or otherwise adjust the converted Tiptap JSON as needed. |
| Editor Insertion | If you want to rely on the extension's default insertion behavior (replacing the editor content), you can call the setEditorContent() function provided in the callback. If you modify the content yourself, you must manually set it with editor.commands.setContent(content). |
Headers & Footers
When importing a .docx file that contains headers and footers, the import extension automatically detects and applies them if the Pages extension is installed.
Automatic handling
If the Pages extension is registered in your editor, headers and footers are applied automatically when you call setEditorContent():
editor
.chain()
.import({
file,
onImport(context) {
if (context.error) {
console.error(context.error)
return
}
// Headers and footers are applied automatically alongside the body content
context.setEditorContent()
},
})
.focus()
.run()If the Pages extension is not installed, the header and footer data is silently ignored and the body content is imported as usual.
Manual handling
The onImport callback provides all header and footer fields for manual processing:
editor
.chain()
.import({
file,
onImport(context) {
if (context.error) {
console.error(context.error)
return
}
// Access header/footer data directly
const {
header, // Default header (Tiptap JSON or null)
footer, // Default footer (Tiptap JSON or null)
headerFirstPage, // First page header (Tiptap JSON or null)
footerFirstPage, // First page footer (Tiptap JSON or null)
headerOdd, // Odd page header (Tiptap JSON or null)
footerOdd, // Odd page footer (Tiptap JSON or null)
headerEven, // Even page header (Tiptap JSON or null)
footerEven, // Even page footer (Tiptap JSON or null)
} = context
// Set body content without automatic header/footer application
editor.commands.setContent(context.content)
// Manually apply headers and footers via Pages extension commands
if (header) editor.commands.setHeader(header)
if (footer) editor.commands.setFooter(footer)
if (headerFirstPage || footerFirstPage) {
editor.commands.setDifferentFirstPage(true)
if (headerFirstPage) editor.commands.setHeaderFirstPage(headerFirstPage)
if (footerFirstPage) editor.commands.setFooterFirstPage(footerFirstPage)
}
if (headerOdd || headerEven || footerOdd || footerEven) {
editor.commands.setDifferentOddEven(true)
if (headerOdd) editor.commands.setHeaderOdd(headerOdd)
if (headerEven) editor.commands.setHeaderEven(headerEven)
if (footerOdd) editor.commands.setFooterOdd(footerOdd)
if (footerEven) editor.commands.setFooterEven(footerEven)
}
},
})
.focus()
.run()Available fields
| Field | Description |
|---|---|
header | Default header content as Tiptap JSON, or null |
footer | Default footer content as Tiptap JSON, or null |
headerFirstPage | First page header (when "Different First Page" is enabled in Word), or null |
footerFirstPage | First page footer (when "Different First Page" is enabled in Word), or null |
headerOdd | Odd page header (when "Different Odd & Even Pages" is enabled in Word), or null |
footerOdd | Odd page footer (when "Different Odd & Even Pages" is enabled in Word), or null |
headerEven | Even page header (when "Different Odd & Even Pages" is enabled in Word), or null |
footerEven | Even page footer (when "Different Odd & Even Pages" is enabled in Word), or null |
Footnotes & Endnotes
When importing a .docx file that contains footnotes or endnotes, the import extension returns them in the onImport callback alongside the document content.
Accessing footnote and endnote data
The onImport callback provides footnotes and endnotes fields for processing:
editor
.chain()
.import({
file,
onImport(context) {
if (context.error) {
console.error(context.error)
return
}
// Access footnote and endnote data
const { footnotes, endnotes } = context
// footnotes and endnotes are objects keyed by note ID
// Each value is a Tiptap JSON document: { type: "doc", content: [...] }
console.log('Footnotes:', footnotes)
console.log('Endnotes:', endnotes)
// Insert the main content into the editor
context.setEditorContent()
},
})
.focus()
.run()Available fields
| Field | Description |
|---|---|
footnotes | An object keyed by footnote ID, where each value is a Tiptap JSON document, or {} if the document has no footnotes |
endnotes | An object keyed by endnote ID, where each value is a Tiptap JSON document, or {} if the document has no endnotes |
Inline references in the document body are represented as footnoteReference and endnoteReference nodes, each with a noteId attribute linking to the corresponding entry.
Verbose output
The DOCX import extension provides a verbose configuration property to help you control the level of diagnostic output during the import process. This is especially useful for debugging or for getting more insight into what happens during conversion.
The verbose property is a bitmask number that determines which types of log messages are emitted. The extension uses the following levels:
| Value | Level | Description |
|---|---|---|
| 1 | log | General informational logs |
| 2 | warn | Warnings |
| 4 | error | Errors |
Verbose bitmask
You can combine levels by adding their values together. For example, verbose: 3 will enable both log (1) and warn (2) messages.
The verbose output will give you, along the data property, one more property called logs, which will contain info, warn, and error properties, each of them being an array with all of the information related to that specific verbosity.
{
"data": {
"content": {
// Tiptap JSON
}
},
"logs": {
"info": [],
"warn": [
{
"message": "Image file not found in media files",
"fileName": "image1.gif",
"availableMediaFiles": []
}
],
"error": [
{
"message": "Image upload failed: General error",
"fileName": "image1.gif",
"url": "https://your-image-upload-endpoint.com",
"error": "Unable to connect. Is the computer able to access the url?",
"context": "uploadImage general error"
}
]
}
}Support & Limitations
Importing .docx files into Tiptap provides a way to handle most standard Word content, but it’s not a one-to-one mapping due to inherent differences between DOCX formatting and Tiptap’s CSS-based styles.
Currently supported features and known limitations:
| Feature | Support |
|---|---|
| Text content | ✓ Basic text, spacing, punctuation |
| Text formatting | ✓ Bold, italic, underline, strikethrough, alignment, line height |
| Block elements | ✓ Paragraphs, headings (1–6), blockquotes, ordered and unordered lists |
| Tables | ✓ Basic structure, header rows, colspan |
| Links | ✓ Hyperlinks |
| Media (Images) | ✓ Embedded images, size preserved |
| Styles | ✓ Font families*, Font colors, font sizes, background colors, line heights |
| Headers & Footers | ✓ Supported (requires Pages extension) |
| Sections & Page Breaks | ~ In development |
| Footnotes & Endnotes | ✓ Supported |
| Math | ~ In development |
| Comments & Revisions | ✗ |
| Table of Contents | ✗ |
| Advanced Formatting | ✗ Columns, text direction, forms, macros, embedded scripts |
| Metadata | ✗ |
| Text Boxes, Shapes, SmartArt | ✗ |
.docx file is opened.