Plate
PlateEditorsTemplates
GitHub16kGitHub
DiscordDiscord
  • Feature Kits
  • Upload Files
  • Plugin
    • Plugin Methods
    • Plugin Shortcuts
    • Plugin Context
    • Plugin Components
    • Plugin Rules
    • Editing Behavior
    • Plugin Input Rules
  • Editor
    • Editor Methods
    • Controlled Value
  • Authored Changes
  • Performance
  • Static Rendering
  • HTML
  • Markdown
  • Form
  • TypeScript
  • Debugging
  • Unit Testing
  • Browser
  • Troubleshooting
  • Locations
  • Transactions
  • Serializing
  • Roots
  • Document Meta
  • Clipboard and Paste
  • Decorations and annotations
  • Schema
  • History
  • PaginationExperimental
  • Annotations
  • DOM Coverage
  • External Text Views
  • Virtualized Rendering

Serializing

PreviousNext

Save complete Plate documents and convert them to text, HTML, Markdown, or DOCX.

Save Plate JSON when another Plate editor must recover the editable document. Use a format parser or serializer when content crosses an application boundary.

Choose a surface

TaskSurface
Persist the complete editor document, pending proposals includededitor.read.value()
Export a clean accepted or proposed documentprojectAuthoredDocument from platejs/authored
Convert semantic HTMLplatejs/html; Node parsing uses
TransactionsRoots

On This Page

Choose a surfaceSave Plate JSONSerialize plain textConvert HTMLConvert MarkdownConvert DOCXHandle resultsDefine feature mappingsDocument and slice authority
Build your editor
Production-ready AI template and reusable components.
Get all-access
platejs/html/server
Convert Markdownplatejs/markdown
Import or export Wordplatejs/docx/import and platejs/docx/export
Render component-styled HTMLplatejs/static
Exchange browser clipboard MIME payloadsDataTransferFormat through platejs/dom

There is no universal document converter. Each format owns its syntax, diagnostics, loss policy, limits, and retained source.

Save Plate JSON

editor.read.value() includes the primary children, named roots, and persistent metadata.

const document = editor.read.value();
const schema = editor.read.schema.identity();
 
await saveDocument({ document, schema });
const document = editor.read.value();
const schema = editor.read.schema.identity();
 
await saveDocument({ document, schema });

Saving only children drops roots and metadata. Persist an application schema identity when stored documents require versioned migration. Validate migrated data before publishing it to an editor.

The saved value also holds the authored review: each node's pending review marks in its authored property and the review records in the document's records. Loading it into an editor that installs AuthoredPlugin restores the pending proposals. To save a clean document instead, project it:

import { projectAuthoredDocument } from 'platejs/authored';
 
const accepted = projectAuthoredDocument(editor.read.value(), {
  projection: 'accepted',
});
import { projectAuthoredDocument } from 'platejs/authored';
 
const accepted = projectAuthoredDocument(editor.read.value(), {
  projection: 'accepted',
});

HTML and Markdown carry no review. Every HTML, Markdown, plain-text and static HTML export of a document with pending changes throws a TypeError unless projection is 'accepted' or 'proposed'. A document without pending changes needs no projection.

Serialize plain text

import { serializePlainText } from 'platejs';
 
const result = serializePlainText(editor, { projection: 'accepted' });
import { serializePlainText } from 'platejs';
 
const result = serializePlainText(editor, { projection: 'accepted' });

Feature plugins contribute structural plainText mappings through formats/defineFormats. Plain text is one-way output; it does not become a universal parser or persistence format.

Convert HTML

Use direct functions for detached work:

import { parseHtml, serializeHtml } from 'platejs/html';
 
const parsed = parseHtml(source, { plugins: EditorKit });
const output = serializeHtml(document, {
  plugins: EditorKit,
  projection: 'accepted',
});
import { parseHtml, serializeHtml } from 'platejs/html';
 
const parsed = parseHtml(source, { plugins: EditorKit });
const output = serializeHtml(document, {
  plugins: EditorKit,
  projection: 'accepted',
});

In Node.js, import parseHtml from platejs/html/server. Install linkedom for that server-only DOM adapter.

Install HtmlPlugin when a configured editor should expose editor.api.html.parse, parseSlice, and serialize. See HTML.

Convert Markdown

import { parseMarkdown, serializeMarkdown } from 'platejs/markdown';
 
const parsed = parseMarkdown(source, { plugins: EditorKit });
const output = serializeMarkdown(document, {
  plugins: EditorKit,
  projection: 'proposed',
});
import { parseMarkdown, serializeMarkdown } from 'platejs/markdown';
 
const parsed = parseMarkdown(source, { plugins: EditorKit });
const output = serializeMarkdown(document, {
  plugins: EditorKit,
  projection: 'proposed',
});

Install MarkdownPlugin for editor.api.markdown.parse, parseSlice, parseInline, and serialize. See Markdown.

Convert DOCX

DOCX import is detached. Supply the complete plugin target before the operation starts, then publish a successful document explicitly.

import { importDocx } from 'platejs/docx/import';
 
const result = await importDocx(file, { plugins: EditorKit });
 
if (result.ok) {
  editor.update((tx) => tx.value.replace(result.document));
}
import { importDocx } from 'platejs/docx/import';
 
const result = await importDocx(file, { plugins: EditorKit });
 
if (result.ok) {
  editor.update((tx) => tx.value.replace(result.document));
}

DOCX export captures a configured editor because static rendering, comments, retained source, and Word revisions are part of its package workflow.

import { exportDocx } from 'platejs/docx/export';
import { BaseEditorKit } from '@/components/editor/plugins-static';
 
const result = await exportDocx(editor, {
  presentation: BaseEditorKit,
  projection: 'review',
});
import { exportDocx } from 'platejs/docx/export';
import { BaseEditorKit } from '@/components/editor/plugins-static';
 
const result = await exportDocx(editor, {
  presentation: BaseEditorKit,
  projection: 'review',
});

A live editor's components are editing UI, so pass the app's static kit as presentation to draw the file.

A Word file contains the visible Word document, its comments, and its tracked revisions. A review export also stores the reviewed blocks and review records in a custom XML part that a Plate import restores. Save Plate JSON beside it when another Plate editor must recover named roots or metadata.

See DOCX for cancellation, package limits, comments, and retained source.

Handle results

HTML, Markdown, and DOCX use format-specific diagnosed results. Success carries warnings and the requested document, slice, string, or Blob. Failure carries a nonempty error-first diagnostic tuple and no publishable carrier.

const result = editor.api.markdown.serialize({ projection: 'accepted' });
 
showDiagnostics(result.diagnostics);
if (!result.ok) return;
 
downloadMarkdown(result.data);
const result = editor.api.markdown.serialize({ projection: 'accepted' });
 
showDiagnostics(result.diagnostics);
if (!result.ok) return;
 
downloadMarkdown(result.data);

Expected source failure and representational loss return diagnostics. Configuration errors, mapping bugs, and invalid serializer model data throw. lossPolicy defaults to 'reject'; opt into 'allow' only when the caller accepts the exact reported loss.

Define feature mappings

Feature plugins declare semantic mappings through formats and defineFormats using the html, markdown, and plainText keys. The narrow authoring callback cannot read a live editor or store.

Whole browser MIME payloads use DataTransferFormat, not feature mappings. Clipboard insertion remains destination-aware and can preserve native open edges and detached roots. See Plugin Methods and Clipboard.

Document and slice authority

A complete parse returns EditorDocumentValue. Direct syntax slice or inline parsing returns a closed, rootless ContentSlice. The insertion owner fits that slice once the destination is known.

const result = editor.api.markdown.parseSlice(source);
 
if (result.ok) editor.update.slice.replace(result.slice);
const result = editor.api.markdown.parseSlice(source);
 
if (result.ok) editor.update.slice.replace(result.slice);

Do not turn a complete document into children before replacement; that drops named roots and metadata. Do not invent a destination during detached parsing.