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
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
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 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
**Bold text**
*Italic text*
`Code text`
~~Strikethrough~~
Links
[Link text](https://example.com)
Images

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