A .NET library for converting CommonMark markdown to Microsoft Word (.docx) documents with syntax highlighting and Mermaid diagrams. Supports headings, paragraphs, emphasis, code blocks with syntax highlighting (JSON, TypeSpec, Bash), Mermaid diagram rendering, links, images, lists, tables, and more.
$ dotnet add package SpecWorks.MarkMyWordA .NET 9 library for bidirectional conversion between CommonMark/GitHub Flavored Markdown and Microsoft Word (.docx) documents.
MarkMyWord provides bidirectional conversion between Markdown and Word:
✅ Block Elements
# H1 through ###### H6, Setext: underlined)>)---, ***, ___)✅ Inline Elements
**text** or __text__)*text* or _text_)***text***)`code`)[text](url)) - supports local files and URLs with fallback)\ at end of line)✅ Styling
✅ Supported Elements
# through ######)**bold**, *italic*)`code`)[text](url) syntax with optional extraction```> prefix✅ Conversion Options
dotnet add package MarkMyWord
using MarkMyWord;
// Convert markdown string to .docx file
string markdown = "# Hello World\n\nThis is **bold** text.";
MarkdownConverter.ConvertToDocx(markdown, "output.docx");
using MarkMyWord;
using MarkMyWord.Configuration;
// Convert Word document to markdown file
WordConverter.ConvertToMarkdown("input.docx", "output.md");
// With options for LLM grounding
var options = new WordToMarkdownOptions
{
Flavor = MarkdownFlavor.GitHubFlavoredMarkdown,
OptimizeForLLM = true,
ExtractImages = true,
IncludeMetadata = false
};
WordConverter.ConvertToMarkdown("document.docx", "output.md", options);
// Convert to string
string markdown = WordConverter.ConvertToMarkdownString("document.docx");
// Get the document as a byte array (useful for web scenarios)
byte[] docxBytes = MarkdownConverter.ConvertToDocxBytes(markdown);
// Convert from stream to stream
using var inputStream = File.OpenRead("input.md");
using var outputStream = File.Create("output.docx");
MarkdownConverter.ConvertToDocx(inputStream, outputStream);
// Async conversion
await MarkdownConverter.ConvertToDocxAsync(markdown, "output.docx");
// Unordered list
string unorderedList = @"
# Shopping List
- Apples
- Bananas
- Oranges
- Naval oranges
- Blood oranges
";
MarkdownConverter.ConvertToDocx(unorderedList, "shopping.docx");
// Ordered list
string orderedList = @"
# Instructions
1. Preheat oven to 350°F
2. Mix ingredients
3. Bake for 30 minutes
1. Check at 25 minutes
2. Test with toothpick
4. Let cool
";
MarkdownConverter.ConvertToDocx(orderedList, "instructions.docx");
MarkMyWord includes a powerful CLI for converting markdown files from the command line.
dotnet tool install --global SpecWorks.MarkMyWord.CLI
Or run directly from the project:
dotnet run --project src/MarkMyWord.CLI/MarkMyWord.CLI.csproj -- [command] [options]
The CLI automatically detects the conversion direction based on file extension:
.md or .markdown input → converts to Word (.docx).docx input → converts to Markdown (.md)Markdown to Word:
markmyword convert -i README.md
markmyword convert -i input.md -o output.docx
Word to Markdown:
markmyword convert -i document.docx
markmyword convert -i input.docx -o output.md
Specify output file:
markmyword convert -i input.md -o output.docx
Custom font and size:
markmyword convert -i document.md --font "Times New Roman" --font-size 12
Use custom style configuration:
markmyword convert -i document.md --style custom-style.json
Verbose output:
markmyword convert -i document.md -v
Force overwrite:
markmyword convert -i document.md --force
Word to Markdown with options:
# Convert Word to GitHub Flavored Markdown (default)
markmyword convert -i document.docx -o output.md
# Convert to strict CommonMark
markmyword convert -i document.docx --commonmark
# Optimize for LLM grounding (clean, semantic output)
markmyword convert -i document.docx --optimize-llm
# Include document metadata as YAML frontmatter
markmyword convert -i document.docx --include-metadata
# Don't extract images
markmyword convert -i document.docx --extract-images false
View version:
markmyword version
Get help:
markmyword --help
markmyword convert --help
| Option | Alias | Description |
|---|---|---|
--input | -i | Input file path (.md or .docx) (required) |
--output | -o | Output file path (auto-detects extension) |
--verbose | -v | Enable verbose output |
--force | - | Overwrite output file if it exists |
| Option | Alias | Description |
|---|---|---|
--font | -f | Default font name (e.g., 'Calibri') |
--font-size | -s | Default font size (6-72 points) |
--style | - | Path to JSON style configuration file |
| Option | Description | Default |
|---|---|---|
--to-markdown | Explicitly convert to Markdown (auto-detected) | false |
--extract-images | Extract and save embedded images | true |
--optimize-llm | Optimize output for LLM grounding | true |
--commonmark | Use strict CommonMark instead of GFM | false |
--include-metadata | Include document metadata as YAML frontmatter | false |
using MarkMyWord;
using MarkMyWord.Configuration;
// Configure Word to Markdown conversion
var options = new WordToMarkdownOptions
{
// Use GitHub Flavored Markdown (supports tables, strikethrough, etc.)
Flavor = MarkdownFlavor.GitHubFlavoredMarkdown,
// Optimize for LLM grounding (clean, semantic content)
OptimizeForLLM = true,
// Extract embedded images to files
ExtractImages = true,
// Directory for extracted images (default: same as output file)
ImageOutputDirectory = "./images",
// URL prefix for image links in markdown
ImageUrlPrefix = "https://example.com/images/",
// Include document metadata as YAML frontmatter
IncludeMetadata = true,
// Preserve formatting metadata for roundtripping
PreserveFormattingMetadata = false,
// Use HTML for complex formatting when no markdown equivalent exists
UseHtmlForComplexFormatting = false,
// Line ending style
LineEndings = LineEndingStyle.LF
};
WordConverter.ConvertToMarkdown("document.docx", "output.md", options);
using MarkMyWord.Configuration;
var options = new ConversionOptions
{
Styles = new StyleConfiguration
{
DefaultFontName = "Georgia",
DefaultFontSize = 12,
CodeFontName = "Fira Code",
CodeFontSize = 10,
CodeBackgroundColor = "F5F5F5",
QuoteLeftBorderColor = "4A90E2",
QuoteBackgroundColor = "EEF7FF"
}
};
MarkdownConverter.ConvertToDocx(markdown, "output.docx", options);
var options = new ConversionOptions
{
Styles = new StyleConfiguration
{
HeadingStyles = new[]
{
new HeadingStyle
{
Level = 1,
FontSize = 24,
Bold = true,
Color = "2E74B5",
SpacingBeforeTwips = 480, // 1/3 inch
SpacingAfterTwips = 240 // 1/6 inch
},
// ... configure levels 2-6
}
}
};
You can define styles in a JSON file and load them using the CLI or programmatically:
custom-style.json:
{
"styles": {
"defaultFontName": "Georgia",
"defaultFontSize": 12,
"headingStyles": [
{
"level": 1,
"fontSize": 28,
"bold": true,
"color": "2E74B5",
"spacingBeforeTwips": 480,
"spacingAfterTwips": 240
},
{
"level": 2,
"fontSize": 20,
"bold": true,
"color": "2E74B5",
"spacingBeforeTwips": 400,
"spacingAfterTwips": 200
},
{
"level": 3,
"fontSize": 16,
"bold": true,
"color": "1F4D78",
"spacingBeforeTwips": 320,
"spacingAfterTwips": 160
}
],
"codeFontName": "Fira Code",
"codeFontSize": 10,
"codeBackgroundColor": "282C34",
"quoteLeftBorderColor": "4A90E2",
"quoteLeftBorderWidth": 4,
"quoteBackgroundColor": "EEF7FF",
"listIndentationTwips": 720
}
}
Use with CLI:
markmyword convert -i document.md --style custom-style.json
Load programmatically:
using System.Text.Json;
var json = File.ReadAllText("custom-style.json");
var config = JsonSerializer.Deserialize<ConversionOptions>(json);
MarkdownConverter.ConvertToDocx(markdown, "output.docx", config);
Notes:
# prefixvar options = new ConversionOptions
{
DocumentTitle = "My Document",
Author = "John Doe",
Subject = "Technical Documentation"
};
MarkdownConverter.ConvertToDocx(markdown, "output.docx", options);
MarkMyWord uses a three-stage conversion pipeline:
Markdown Text
↓
Markdig Parser
↓
AST (Syntax Tree)
↓
OpenXmlRenderer
↓
OpenXML Elements
↓
Word Document (.docx)
MarkMyWord/
├── src/
│ ├── MarkMyWord/ # Core library
│ │ ├── MarkdownConverter.cs # Public API
│ │ ├── Converters/
│ │ │ ├── OpenXmlRenderer.cs # Main renderer
│ │ │ ├── BlockRenderers/ # Block element renderers
│ │ │ │ ├── CodeBlockRenderer.cs # Code block rendering
│ │ │ │ ├── ListRenderer.cs # List rendering
│ │ │ │ └── TableRenderer.cs # Table rendering
│ │ │ └── InlineRenderers/ # Inline element renderers
│ │ │ └── LinkInlineRenderer.cs # Links & images
│ │ ├── SyntaxHighlighting/ # Syntax highlighting
│ │ │ ├── ISyntaxHighlighter.cs # Highlighter interface
│ │ │ ├── ColorCodeHighlighter.cs # JSON highlighting
│ │ │ ├── TypeSpecHighlighter.cs # TypeSpec highlighting
│ │ │ ├── BashHighlighter.cs # Bash/Shell highlighting
│ │ │ └── SyntaxHighlighterFactory.cs
│ │ ├── OpenXml/
│ │ │ ├── DocumentBuilder.cs # OpenXML document builder
│ │ │ ├── StyleManager.cs # Style management
│ │ │ └── ListManager.cs # List numbering management
│ │ └── Configuration/ # Configuration classes
│ └── MarkMyWord.CLI/ # Command-line tool
└── tests/
└── MarkMyWord.Tests/ # Unit tests (29 tests)
git clone https://github.com/yourusername/MarkMyWord.git
cd MarkMyWord
dotnet build
dotnet test
var markdown = File.ReadAllText("README.md");
MarkdownConverter.ConvertToDocx(markdown, "README.docx");
string markdown = @"
# Shopping List
## Groceries
- Milk
- Eggs
- Bread
## Tasks
1. Buy groceries
2. Clean house
3. Do laundry
- Whites
- Colors
";
MarkdownConverter.ConvertToDocx(markdown, "shopping-list.docx");
string markdown = @"
# Product Documentation

Our product features:


";
MarkdownConverter.ConvertToDocx(markdown, "product-doc.docx");
string markdown = @"
# Sales Report
| Product | Q1 Sales | Q2 Sales | Total |
|---------|----------|----------|-------|
| Widget A | $1,000 | $1,200 | $2,200 |
| Widget B | $850 | $900 | $1,750 |
| Widget C | $1,500 | $1,600 | $3,100 |
";
MarkdownConverter.ConvertToDocx(markdown, "sales-report.docx");
MarkMyWord supports syntax highlighting for code blocks, making code more readable in Word documents:
Supported Languages:
Example:
string markdown = @"
# API Response
```json
{
""name"": ""MarkMyWord"",
""version"": ""0.2.0"",
""enabled"": true
}
#!/bin/bash
echo ""Converting files...""
for file in *.md; do
markmyword convert -i ""$file""
done
";
MarkdownConverter.ConvertToDocx(markdown, "highlighted.docx");
**Features:**
- Colors optimized for grey code block backgrounds
- Automatic spell/grammar check suppression (no red squiggles!)
- Trailing empty lines automatically removed
- Property names vs values distinguished in JSON
**Disable syntax highlighting:**
```csharp
var options = new ConversionOptions
{
EnableSyntaxHighlighting = false
};
MarkdownConverter.ConvertToDocx(markdown, "plain-code.docx", options);
Custom syntax colors:
var options = new ConversionOptions
{
Styles = new StyleConfiguration
{
SyntaxColorScheme = new SyntaxColorScheme
{
KeywordColor = "0000FF", // Blue
StringColor = "A31515", // Red
NumberColor = "098658", // Green
CommentColor = "6A9955", // Green
TypeColor = "4EC9B0", // Cyan
FunctionColor = "C4A000" // Gold
}
}
};
var options = new ConversionOptions
{
Styles = new StyleConfiguration
{
CodeFontName = "Consolas",
CodeFontSize = 9,
CodeBackgroundColor = "F5F5F5" // Light grey
}
};
string code = @"
# Code Example
```json
{
""message"": ""Hello, World!""
}
";
MarkdownConverter.ConvertToDocx(code, "code.docx", options);
## Testing
The library includes comprehensive unit tests covering all supported markdown syntax:
```bash
dotnet test
Current test coverage (29 tests):
MarkMyWord implements:
Contributions are welcome! Areas for contribution:
MIT License - See LICENSE file for details
🚀 Beta - Core functionality and CLI are fully working with comprehensive CommonMark support.
Fully supported:
Coming soon: Task lists, footnotes, definition lists
Generated with ❤️ using Claude Code