Overview
The @lexical/markdown package provides bidirectional conversion between Lexical editor state and Markdown, plus live Markdown shortcuts during editing.
Installation
npm install @lexical/markdown
This package requires @lexical/code, @lexical/link, @lexical/list, and @lexical/rich-text for full functionality.
Core Functions
$convertFromMarkdownString
Converts Markdown string to Lexical nodes.
function $convertFromMarkdownString(
markdown: string,
transformers?: Array<Transformer>,
node?: ElementNode,
shouldPreserveNewLines?: boolean,
shouldMergeAdjacentLines?: boolean
): void
The Markdown string to convert
transformers
Transformer[]
default:"TRANSFORMERS"
Custom transformers to use for conversion
Target node to append content to (defaults to root)
Whether to preserve line breaks in conversion
Whether to merge adjacent non-empty lines per CommonMark spec
Example:
import { $convertFromMarkdownString, TRANSFORMERS } from '@lexical/markdown';
editor.update(() => {
const markdown = `# Hello World\n\nThis is **bold** text.`;
$convertFromMarkdownString(markdown, TRANSFORMERS);
});
$convertToMarkdownString
Converts Lexical editor state to Markdown string.
function $convertToMarkdownString(
transformers?: Array<Transformer>,
node?: ElementNode,
shouldPreserveNewLines?: boolean
): string
transformers
Transformer[]
default:"TRANSFORMERS"
Custom transformers to use for conversion
Source node to convert (defaults to root)
Whether to preserve line breaks in output
Returns: Markdown string
Example:
import { $convertToMarkdownString, TRANSFORMERS } from '@lexical/markdown';
editor.getEditorState().read(() => {
const markdown = $convertToMarkdownString(TRANSFORMERS);
console.log(markdown);
});
Markdown Shortcuts
registerMarkdownShortcuts
Registers live Markdown shortcuts (e.g., typing **text** creates bold).
function registerMarkdownShortcuts(
editor: LexicalEditor,
transformers: Array<Transformer>
): () => void
Transformers to enable as shortcuts
Returns: Cleanup function
Example:
import { registerMarkdownShortcuts, TRANSFORMERS } from '@lexical/markdown';
const unregister = registerMarkdownShortcuts(editor, TRANSFORMERS);
// Now typing **bold** will create bold text
// Typing # at line start creates heading
// etc.
Text Format Transformers
Transformers for inline text formatting:
BOLD_STAR
Bold text with **text** or __text__
const BOLD_STAR: TextFormatTransformer
const BOLD_UNDERSCORE: TextFormatTransformer
ITALIC_STAR
Italic text with *text* or _text_
const ITALIC_STAR: TextFormatTransformer
const ITALIC_UNDERSCORE: TextFormatTransformer
BOLD_ITALIC_STAR
Bold and italic with ***text*** or ___text___
const BOLD_ITALIC_STAR: TextFormatTransformer
const BOLD_ITALIC_UNDERSCORE: TextFormatTransformer
STRIKETHROUGH
Strikethrough with ~~text~~
const STRIKETHROUGH: TextFormatTransformer
HIGHLIGHT
Highlight with ==text==
const HIGHLIGHT: TextFormatTransformer
INLINE_CODE
Inline code with `code`
const INLINE_CODE: TextFormatTransformer
Text Match Transformers
Transformers for special patterns:
LINK
Links with [text](url)
const LINK: TextMatchTransformer
Transformers for block elements:
HEADING
Headings with #, ##, etc.
const HEADING: ElementTransformer
Supports: h1 through h6
QUOTE
Block quotes with >
const QUOTE: ElementTransformer
ORDERED_LIST
Ordered lists with 1., 2., etc.
const ORDERED_LIST: ElementTransformer
UNORDERED_LIST
Unordered lists with -, *, or +
const UNORDERED_LIST: ElementTransformer
CHECK_LIST
Check lists with - [ ] or - [x]
const CHECK_LIST: ElementTransformer
CODE
Code blocks with triple backticks
const CODE: MultilineElementTransformer
Supports: Language specifier (```javascript)
Complete set of all transformers.
const TRANSFORMERS: Array<Transformer>
Includes all text format, text match, element, and multiline transformers.
TEXT_FORMAT_TRANSFORMERS
All text formatting transformers.
const TEXT_FORMAT_TRANSFORMERS: Array<TextFormatTransformer>
TEXT_MATCH_TRANSFORMERS
All text match transformers (links).
const TEXT_MATCH_TRANSFORMERS: Array<TextMatchTransformer>
All block element transformers.
const ELEMENT_TRANSFORMERS: Array<ElementTransformer>
All multiline transformers (code blocks).
const MULTILINE_ELEMENT_TRANSFORMERS: Array<MultilineElementTransformer>
You can create custom transformers for specific patterns:
TextFormatTransformer
type TextFormatTransformer = {
format: TextFormatType[];
tag: string;
intraword?: boolean;
type: 'text-format';
}
TextMatchTransformer
type TextMatchTransformer = {
dependencies: Array<Class<LexicalNode>>;
export: (node: LexicalNode, exportChildren: (node: ElementNode) => string, exportFormat: (node: TextNode) => string) => string | null;
importRegExp: RegExp;
regExp: RegExp;
replace: (textNode: TextNode, match: RegExpMatchArray) => void;
trigger: string;
type: 'text-match';
}
type ElementTransformer = {
dependencies: Array<Class<LexicalNode>>;
export: (node: LexicalNode, exportChildren: (node: ElementNode) => string) => string | null;
regExp: RegExp;
replace: (parentNode: ElementNode, children: Array<LexicalNode>, match: RegExpMatchArray, isImport: boolean) => void;
type: 'element';
}
type MultilineElementTransformer = {
dependencies: Array<Class<LexicalNode>>;
export: (node: LexicalNode, exportChildren: (node: ElementNode) => string) => string | null;
regExpEnd: RegExp;
regExpStart: RegExp;
replace: (rootNode: ElementNode, children: Array<LexicalNode>, startMatch: RegExpMatchArray, endMatch: RegExpMatchArray, isImport: boolean) => void;
type: 'multiline-element';
}
Complete Example
import { createEditor } from 'lexical';
import {
$convertFromMarkdownString,
$convertToMarkdownString,
registerMarkdownShortcuts,
TRANSFORMERS
} from '@lexical/markdown';
import { HeadingNode, QuoteNode } from '@lexical/rich-text';
import { CodeNode } from '@lexical/code';
import { LinkNode } from '@lexical/link';
import { ListNode, ListItemNode } from '@lexical/list';
const editor = createEditor({
nodes: [
HeadingNode,
QuoteNode,
CodeNode,
LinkNode,
ListNode,
ListItemNode
]
});
editor.setRootElement(document.getElementById('editor'));
// Enable Markdown shortcuts
const unregisterShortcuts = registerMarkdownShortcuts(editor, TRANSFORMERS);
// Import Markdown
const markdown = `
# My Document
This is **bold** and *italic* text.
- List item 1
- List item 2
\`\`\`javascript
const x = 42;
\`\`\`
`;
editor.update(() => {
$convertFromMarkdownString(markdown, TRANSFORMERS);
});
// Export to Markdown
function exportMarkdown() {
editor.getEditorState().read(() => {
const markdown = $convertToMarkdownString(TRANSFORMERS);
console.log(markdown);
return markdown;
});
}
// Later, cleanup
unregisterShortcuts();
import type { TextFormatTransformer } from '@lexical/markdown';
// Custom transformer for underline with __text__
const UNDERLINE: TextFormatTransformer = {
format: ['underline'],
tag: '__',
type: 'text-format'
};
// Use with custom transformer set
const customTransformers = [
...TRANSFORMERS,
UNDERLINE
];
registerMarkdownShortcuts(editor, customTransformers);