Skip to main content
Yoopta Editor provides built-in support for exporting and importing content in multiple formats including HTML, Markdown, Plain Text, Email, and JSON.

Installation

npm install @yoopta/exports
The exports package is built on top of the editor’s parser APIs.

Export Methods

All export methods are available directly on the editor instance:
import { createYooptaEditor } from '@yoopta/editor';

const editor = createYooptaEditor({ plugins, marks });
const content = editor.getEditorValue();

// Export to different formats
const html = editor.getHTML(content);
const markdown = editor.getMarkdown(content);
const plainText = editor.getPlainText(content);
const email = editor.getEmail(content);
const json = editor.getYooptaJSON(content);

HTML Export

Export content as HTML with semantic markup:
const html = editor.getHTML(editor.getEditorValue());

console.log(html);
// Output:
// <h1>My Title</h1>
// <p>This is a <strong>paragraph</strong> with <em>formatting</em>.</p>
// <ul>
//   <li>Item 1</li>
//   <li>Item 2</li>
// </ul>

HTML with Metadata

HTML export includes block metadata like alignment and depth:
// A paragraph with custom alignment
{
  id: 'block-1',
  type: 'Paragraph',
  value: [...],
  meta: { align: 'center', depth: 1 }
}

// Exports to:
<p data-meta-align="center" 
   data-meta-depth="1" 
   style="margin-left: 20px; text-align: center">
  Content here
</p>

Markdown Export

Export to GitHub Flavored Markdown:
const markdown = editor.getMarkdown(editor.getEditorValue());

console.log(markdown);
// Output:
// # My Title
// 
// This is a **paragraph** with _formatting_.
// 
// - Item 1
// - Item 2
// 
// ```javascript
// const hello = 'world';
// ```

Markdown Features

  • Headings (#, ##, ###)
  • Bold and italic formatting
  • Lists (bulleted and numbered)
  • Code blocks with language syntax
  • Blockquotes
  • Links and images
  • Tables
  • Horizontal rules

Plain Text Export

Export content as plain text (no formatting):
const text = editor.getPlainText(editor.getEditorValue());

console.log(text);
// Output:
// My Title
// This is a paragraph with formatting.
// Item 1
// Item 2
Useful for:
  • Search indexing
  • Character/word count
  • Preview text
  • Clipboard copy

Email Export

Export HTML optimized for email clients:
const emailHtml = editor.getEmail(editor.getEditorValue(), {
  title: 'Newsletter Title',
  previewText: 'This appears in email previews',
  styles: {
    container: {
      maxWidth: '600px',
      fontFamily: 'Arial, sans-serif',
    },
  },
});

Email Template Options

type EmailTemplateOptions = {
  /** Email subject/title */
  title?: string;
  
  /** Preview text shown in inbox */
  previewText?: string;
  
  /** Custom CSS styles */
  styles?: {
    container?: React.CSSProperties;
    heading?: React.CSSProperties;
    paragraph?: React.CSSProperties;
  };
};
The email export uses inline styles and table-based layouts for maximum compatibility.

JSON Export

Export the native Yoopta content structure:
const json = editor.getYooptaJSON(editor.getEditorValue());
const jsonString = JSON.stringify(json, null, 2);

// Save to file
const blob = new Blob([jsonString], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'content.json';
a.click();

Import Methods

The exports package provides deserializers for importing content:
import { html, markdown, plainText } from '@yoopta/exports';

// Import from HTML
const htmlContent = html.deserialize(editor, htmlString);
editor.setEditorValue(htmlContent);

// Import from Markdown
const mdContent = markdown.deserialize(editor, markdownString);
editor.setEditorValue(mdContent);

// Import from Plain Text
const textContent = plainText.deserialize(editor, plainTextString);
editor.setEditorValue(textContent);

HTML Import

import { html } from '@yoopta/exports';

const htmlString = `
  <h1>Title</h1>
  <p>Paragraph with <strong>bold</strong> text.</p>
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
  </ul>
`;

const content = html.deserialize(editor, htmlString);
editor.setEditorValue(content);
Supported HTML tags:
  • Headings: <h1> - <h6>
  • Paragraphs: <p>
  • Lists: <ul>, <ol>, <li>
  • Formatting: <strong>, <em>, <u>, <s>, <code>
  • Quotes: <blockquote>
  • Code: <pre>, <code>
  • Images: <img>
  • Links: <a>
  • Tables: <table>, <tr>, <td>, <th>

Markdown Import

import { markdown } from '@yoopta/exports';

const mdString = `
# Title

Paragraph with **bold** text.

- Item 1
- Item 2

\`\`\`javascript
const hello = 'world';
\`\`\`
`;

const content = markdown.deserialize(editor, mdString);
editor.setEditorValue(content);

Plain Text Import

import { plainText } from '@yoopta/exports';

const textString = `Title\n\nParagraph 1\nParagraph 2`;

const content = plainText.deserialize(editor, textString);
editor.setEditorValue(content);

Practical Examples

Export Button with Menu

1

Create export handler

const handleExport = (format: 'html' | 'markdown' | 'text' | 'json') => {
  const value = editor.getEditorValue();
  let content = '';

  switch (format) {
    case 'html':
      content = editor.getHTML(value);
      break;
    case 'markdown':
      content = editor.getMarkdown(value);
      break;
    case 'text':
      content = editor.getPlainText(value);
      break;
    case 'json':
      content = JSON.stringify(value, null, 2);
      break;
  }

  // Copy to clipboard or download
  navigator.clipboard.writeText(content);
};
2

Create UI

<DropdownMenu>
  <DropdownMenuTrigger>
    Export
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem onClick={() => handleExport('html')}>
      Export as HTML
    </DropdownMenuItem>
    <DropdownMenuItem onClick={() => handleExport('markdown')}>
      Export as Markdown
    </DropdownMenuItem>
    <DropdownMenuItem onClick={() => handleExport('text')}>
      Export as Plain Text
    </DropdownMenuItem>
    <DropdownMenuItem onClick={() => handleExport('json')}>
      Export as JSON
    </DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Download as File

function downloadFile(content: string, filename: string, mimeType: string) {
  const blob = new Blob([content], { type: mimeType });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = filename;
  a.click();
  URL.revokeObjectURL(url);
}

// Download as Markdown
const markdown = editor.getMarkdown(editor.getEditorValue());
downloadFile(markdown, 'document.md', 'text/markdown');

// Download as HTML
const html = editor.getHTML(editor.getEditorValue());
downloadFile(html, 'document.html', 'text/html');

// Download as JSON
const json = JSON.stringify(editor.getYooptaJSON(editor.getEditorValue()), null, 2);
downloadFile(json, 'document.json', 'application/json');

Import from File Upload

import { markdown } from '@yoopta/exports';

function handleFileUpload(event: React.ChangeEvent<HTMLInputElement>) {
  const file = event.target.files?.[0];
  if (!file) return;

  const reader = new FileReader();
  
  reader.onload = (e) => {
    const text = e.target?.result as string;
    
    // Detect format and import
    if (file.name.endsWith('.md')) {
      const content = markdown.deserialize(editor, text);
      editor.setEditorValue(content);
    } else if (file.name.endsWith('.html')) {
      const content = html.deserialize(editor, text);
      editor.setEditorValue(content);
    } else if (file.name.endsWith('.json')) {
      const content = JSON.parse(text);
      editor.setEditorValue(content);
    }
  };
  
  reader.readAsText(file);
}

// UI
<input
  type="file"
  accept=".md,.html,.json"
  onChange={handleFileUpload}
/>

Live Markdown Preview

function MarkdownPreview() {
  const [markdown, setMarkdown] = useState('');

  useEffect(() => {
    const handler = () => {
      const content = editor.getEditorValue();
      const md = editor.getMarkdown(content);
      setMarkdown(md);
    };

    editor.on('change', handler);
    return () => editor.off('change', handler);
  }, []);

  return (
    <div className="markdown-preview">
      <pre>{markdown}</pre>
    </div>
  );
}

Custom Serializers

Plugins can define custom serialization logic:
const CustomPlugin = new YooptaPlugin({
  type: 'Custom',
  elements: { /* ... */ },
  parsers: {
    html: {
      serialize: (element, text, blockMeta) => {
        const { align = 'left' } = blockMeta || {};
        return `<div class="custom" style="text-align: ${align}">${text}</div>`;
      },
      deserialize: {
        nodeNames: ['DIV'],
        parse: (el, editor) => {
          if (el.className === 'custom') {
            // Return parsed element
          }
        },
      },
    },
    markdown: {
      serialize: (element) => {
        return `> ${element.children[0].text}\n`;
      },
    },
    email: {
      serialize: (element, text, blockMeta) => {
        return `<table><tr><td>${text}</td></tr></table>`;
      },
    },
  },
});

Best Practices

Always validate content structure when importing:
try {
  const content = markdown.deserialize(editor, mdString);
  editor.setEditorValue(content);
} catch (error) {
  console.error('Invalid markdown:', error);
}
For large documents, consider chunking or streaming:
const blocks = Object.values(editor.getEditorValue());
const chunks = [];

for (let i = 0; i < blocks.length; i += 100) {
  const chunk = blocks.slice(i, i + 100);
  chunks.push(editor.getHTML({ ...chunk }));
}
Use HTML import for rich formatting, Markdown for simple content:
// Preserves colors, highlights, etc.
const richContent = html.deserialize(editor, htmlString);

// Simple text formatting only
const simpleContent = markdown.deserialize(editor, mdString);

Build docs developers (and LLMs) love