Skip to main content

Overview

The getMarkdown method converts Yoopta editor content into Markdown string format. It uses plugin-defined Markdown serializers to transform blocks and their content into standard Markdown syntax.

Usage

import { useYooptaEditor } from '@yoopta/editor';

function ExportMarkdownButton() {
  const editor = useYooptaEditor();

  const handleExport = () => {
    const markdown = editor.getMarkdown(editor.children);
    console.log(markdown);
  };

  return <button onClick={handleExport}>Export to Markdown</button>;
}

Signature

function getMarkdown(
  editor: YooEditor,
  content: YooptaContentValue
): string

Parameters

editor
YooEditor
required
The editor instance (automatically provided when called as editor.getMarkdown())
content
YooptaContentValue
required
The content to convert to Markdown. Typically editor.children for current content.

Returns

string - Markdown representation of the content, with blocks separated by newlines

Output Format

Blocks are converted to Markdown and joined with newlines:
# Heading One

This is a paragraph.

## Heading Two

- List item 1
- List item 2

**Bold text** and *italic text*.

Examples

Export to File

function DownloadMarkdown() {
  const editor = useYooptaEditor();

  const handleDownload = () => {
    const markdown = editor.getMarkdown(editor.children);
    
    const blob = new Blob([markdown], { type: 'text/markdown' });
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = 'document.md';
    link.click();
    URL.revokeObjectURL(url);
  };

  return <button onClick={handleDownload}>Download Markdown</button>;
}

Copy to Clipboard

function CopyMarkdownButton() {
  const editor = useYooptaEditor();
  const [copied, setCopied] = useState(false);

  const handleCopy = async () => {
    const markdown = editor.getMarkdown(editor.children);
    await navigator.clipboard.writeText(markdown);
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  };

  return (
    <button onClick={handleCopy}>
      {copied ? 'Copied!' : 'Copy Markdown'}
    </button>
  );
}

Live Markdown Preview

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

  useEffect(() => {
    const handleChange = () => {
      const md = editor.getMarkdown(editor.children);
      setMarkdown(md);
    };

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

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

Export to GitHub

function ExportToGitHub() {
  const editor = useYooptaEditor();

  const handleExport = async () => {
    const markdown = editor.getMarkdown(editor.children);
    
    // Create GitHub issue or update README
    await fetch('https://api.github.com/repos/owner/repo/contents/README.md', {
      method: 'PUT',
      headers: {
        'Authorization': `token ${GITHUB_TOKEN}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        message: 'Update README',
        content: btoa(markdown), // Base64 encode
      }),
    });
  };

  return <button onClick={handleExport}>Export to GitHub</button>;
}

Save to Local Storage

function AutoSaveMarkdown() {
  const editor = useYooptaEditor();

  useEffect(() => {
    const handleChange = () => {
      const markdown = editor.getMarkdown(editor.children);
      localStorage.setItem('document-markdown', markdown);
    };

    // Debounce saves
    const timeoutId = setTimeout(handleChange, 1000);
    return () => clearTimeout(timeoutId);
  }, [editor.children]);

  return null;
}

Export Selected Content

function ExportSelection() {
  const editor = useYooptaEditor();

  const handleExportSelection = () => {
    const selectedPaths = editor.path.selected || [];
    
    if (selectedPaths.length === 0) {
      alert('No blocks selected');
      return;
    }

    const selectedContent = Object.values(editor.children)
      .filter(block => selectedPaths.includes(block.meta.order))
      .reduce((acc, block) => {
        acc[block.id] = block;
        return acc;
      }, {} as YooptaContentValue);

    const markdown = editor.getMarkdown(selectedContent);
    console.log('Selected Markdown:', markdown);
  };

  return <button onClick={handleExportSelection}>Export Selection</button>;
}

Post to API

function PublishButton() {
  const editor = useYooptaEditor();
  const [isPublishing, setIsPublishing] = useState(false);

  const handlePublish = async () => {
    setIsPublishing(true);
    try {
      const markdown = editor.getMarkdown(editor.children);
      
      await fetch('/api/posts', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ 
          content: markdown,
          format: 'markdown',
        }),
      });
      
      alert('Published successfully!');
    } finally {
      setIsPublishing(false);
    }
  };

  return (
    <button onClick={handlePublish} disabled={isPublishing}>
      {isPublishing ? 'Publishing...' : 'Publish'}
    </button>
  );
}

How It Works

Plugin Serializers

Each plugin defines a Markdown serializer:
const ParagraphPlugin = {
  type: 'Paragraph',
  parsers: {
    markdown: {
      serialize: (element, text, meta) => {
        return text; // Simple paragraph
      },
    },
  },
};

const HeadingOnePlugin = {
  type: 'HeadingOne',
  parsers: {
    markdown: {
      serialize: (element, text, meta) => {
        return `# ${text}`; // H1 heading
      },
    },
  },
};

Block Ordering

Blocks are sorted by their meta.order before serialization:
const blocks = blocksData.sort((a, b) => 
  a.meta.order > b.meta.order ? 1 : -1
);

Text Extraction

Text content is extracted from element children:
const text = element.children
  .map(child => child.text)
  .join('');

Common Markdown Patterns

Plugins typically generate these Markdown patterns:

Headings

# Heading 1
## Heading 2
### Heading 3

Lists

- Unordered item
- Another item

1. Ordered item
2. Another item

Formatting

**Bold text**
*Italic text*
`Code text`
~~Strikethrough~~
[Link text](https://example.com)

Images

![Alt text](https://example.com/image.jpg)

Code Blocks

```javascript
const code = 'example';

### Blockquotes

```markdown
> Quoted text
> Another line

Use Cases

  • Documentation: Export to Markdown for README files, docs sites
  • GitHub/GitLab: Create issues, PRs, or update repository files
  • Blog Posts: Export content for static site generators (Jekyll, Hugo, etc.)
  • Note-Taking: Export to Markdown-based note apps (Obsidian, Notion, etc.)
  • Version Control: Store content in Markdown for better diffs
  • Cross-Platform: Share content in universally readable format
  • Backup: Create Markdown backups of content

Limitations

  • Requires plugins to implement Markdown serializers
  • Some complex formatting may be lost (colors, custom styles)
  • Inline elements depend on plugin implementation
  • No standardized Markdown for all block types

See Also

Build docs developers (and LLMs) love