Meziantou.Framework.Markdown 1.0.1

Prefix Reserved
dotnet add package Meziantou.Framework.Markdown --version 1.0.1
                    
NuGet\Install-Package Meziantou.Framework.Markdown -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Meziantou.Framework.Markdown" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Meziantou.Framework.Markdown" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Meziantou.Framework.Markdown" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Meziantou.Framework.Markdown --version 1.0.1
                    
#r "nuget: Meziantou.Framework.Markdown, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Meziantou.Framework.Markdown@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Meziantou.Framework.Markdown&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Meziantou.Framework.Markdown&version=1.0.1
                    
Install as a Cake Tool

Meziantou.Framework.Markdown

Meziantou.Framework.Markdown is a fast, CommonMark compliant, extensible Markdown processor for .NET. It parses Markdown into an abstract syntax tree with precise source locations, and renders it to HTML, plain text, or normalized Markdown. It can also parse and render a document without losing any whitespace (roundtrip).

The library is derived from Markdig by Alexandre Mutel (BSD-2-Clause). See Differences from Markdig and THIRD-PARTY-NOTICES.md.

Install the package

dotnet add package Meziantou.Framework.Markdown

Table of contents

Convert Markdown to HTML

MarkdownConverter is the entry point. Without a pipeline, it uses the plain CommonMark parser:

using Meziantou.Framework.Markdown;

var html = MarkdownConverter.ToHtml("This is a text with some *emphasis*");
// <p>This is a text with some <em>emphasis</em></p>

To write to a TextWriter instead of allocating a string, use the ToHtml(string, TextWriter, ...) overload.

Configure the pipeline

A MarkdownPipeline describes which parsers and renderers are active. Build it once and reuse it: a pipeline is immutable and can be shared between threads.

using Meziantou.Framework.Markdown;

var pipeline = new MarkdownPipelineBuilder()
    .UseAdvancedExtensions()
    .Build();

var html = MarkdownConverter.ToHtml("| a | b |\n|---|---|\n| 1 | 2 |", pipeline);

UseAdvancedExtensions() enables alert blocks, abbreviations, auto-identifiers, citations, custom containers, definition lists, extra emphasis, figures, footers, footnotes, grid tables, mathematics, media links, pipe tables, extra list types, task lists, diagrams, auto-links, and generic attributes.

Each extension can also be enabled on its own:

var pipeline = new MarkdownPipelineBuilder()
    .UsePipeTables()
    .UseTaskLists()
    .UseAutoIdentifiers()
    .Build();

Extensions

Method Description
UseAlertBlocks GitHub alerts: > [!NOTE], > [!TIP], > [!IMPORTANT], > [!WARNING], > [!CAUTION]
UseAbbreviations *[HTML]: Hyper Text Markup Language definitions, rendered as <abbr>
UseAutoIdentifiers Generates an id for each heading
UseAutoLinks Turns http://, https://, ftp://, mailto: and www. text into links
UseBootstrap Adds Bootstrap classes to tables, figures, and blockquotes
UseCitations ""Title"" rendered as <cite>
UseCjkFriendlyEmphasis Emphasis rules adapted to Chinese, Japanese, and Korean text
UseCustomContainers ::: fenced blocks rendered as <div>, and ::inline:: rendered as <span>
UseDefinitionLists Definition lists (<dl>)
UseDiagrams mermaid and nomnoml code blocks rendered as diagram containers
UseEmojiAndSmiley :smile: shortcodes and :) smileys
UseEmphasisExtras ~~strikethrough~~, ~subscript~, ^superscript^, ++inserted++, ==marked==
UseFigures ^^^ blocks rendered as <figure>
UseFooters ^^ blocks rendered as <footer>
UseFootnotes [^1] footnotes
UseGenericAttributes {#id .class key=value} attributes on blocks and inlines. By default, only the attributes that describe the content are written, such as title, lang, alt, colspan, target, role and aria-* (the list is below); pass a filter to allow more. Enable it last.
UseGlobalization Adds dir="rtl" to right-to-left content
UseGridTables Pandoc grid tables
UseJiraLinks PROJECT-123 references rendered as links to a Jira instance
UseListExtras Alphabetical (a.) and roman (i.) ordered lists
UseMathematics $inline$ and $$block$$ math
UseMediaLinks Links to YouTube, Vimeo, and audio or video files rendered as embedded players
UseNonAsciiNoEscape Keeps non-ASCII characters unescaped in URLs
UsePipeTables GitHub-style pipe tables. PipeTableOptions.UseGfmRules enables strict GFM parsing
UsePragmaLines Adds id="pragma-line-N" to the outermost block that starts on each line, to synchronize an editor and a preview
UsePreciseSourceLocation Computes the exact source span of every inline
UseReferralLinks Adds rel values, such as nofollow, to links
UseSmartyPants Typographic quotes, dashes, and ellipses
UseSoftlineBreakAsHardlineBreak Renders every line break as <br />
UseTaskLists - [ ] and - [x] task lists
UseYamlFrontMatter Parses a leading YAML front matter block and excludes it from the output
DisableHtml Treats raw HTML as text
DisableHeadings Disables ATX and setext headings
EnableTrackTrivia Keeps whitespace and trivia for roundtrip
ConfigureNewLine Sets the line ending written by the renderers

The .md files in the test specifications describe the exact syntax and output of each extension.

Security

CommonMark allows raw HTML, and it is copied to the output unchanged. Links are not filtered either: a [link](javascript:alert(1)) produces a javascript: URL. Before you render Markdown from an untrusted source:

  • call DisableHtml() on the pipeline builder, so that raw HTML is written as escaped text,
  • keep the default attribute filter of UseGenericAttributes. It only allows attributes that describe the content: style, data-* and the directive attributes of client-side frameworks (x-init, hx-get...) can run script or cover the page,
  • sanitize the generated HTML (for example with Meziantou.Framework.HtmlSanitizer) to remove unsafe URLs and attributes.

The default attribute filter of UseGenericAttributes allows the attributes that only describe the content: the general attributes that Meziantou.Framework.HtmlSanitizer allows, other than class. They are abbr, align, alt, axis, bgcolor, border, cellpadding, cellspacing, clear, color, cols, colspan, compact, coords, datetime, decoding, dir, face, headers, height, hidden, hreflang, hspace, ismap, lang, language, loading, nohref, nowrap, open, rel, rev, reversed, role, rows, rowspan, rules, scope, scrolling, shape, size, span, start, summary, tabindex, target, title, translate, type, valign, value, vspace, width and aria-*. {#id} and {.class} are always written. When the Markdown is trusted, pass a filter to allow more attributes:

var pipeline = new MarkdownPipelineBuilder()
    .UseAdvancedExtensions()
    .UseGenericAttributes(name => GenericAttributesExtension.IsSafeAttributeName(name) || name.StartsWith("data-", StringComparison.OrdinalIgnoreCase))
    .Build();

Nesting depth is limited so that hostile input cannot overflow the stack: a document nested too deeply throws an ArgumentException instead. Catch it when you process untrusted input.

Work with the syntax tree

MarkdownConverter.Parse returns a MarkdownDocument. Blocks and inlines are MarkdownObject instances, and each one has a Span (offsets in the source text), a Line, and a Column. Lines and columns are zero-based.

using Meziantou.Framework.Markdown;
using Meziantou.Framework.Markdown.Syntax;
using Meziantou.Framework.Markdown.Syntax.Inlines;

var document = MarkdownConverter.Parse("# Title\n\nSee [the docs](https://example.com).");

foreach (var heading in document.Descendants<HeadingBlock>())
{
    Console.WriteLine($"Heading level {heading.Level} at line {heading.Line}");
}

foreach (var link in document.Descendants<LinkInline>())
{
    Console.WriteLine(link.Url);
}

You can change the tree and render it with the same pipeline:

var pipeline = new MarkdownPipelineBuilder().Build();
var document = MarkdownConverter.Parse(markdown, pipeline);
foreach (var link in document.Descendants<LinkInline>())
{
    link.Url = link.Url?.Replace("http://", "https://", StringComparison.Ordinal);
}

var html = document.ToHtml(pipeline);

Other output formats

// Plain text, without any markup
var text = MarkdownConverter.ToPlainText("Some **bold** text");

// Normalized Markdown
var normalized = MarkdownConverter.Normalize("Title\n=====");

For other formats, implement IMarkdownRenderer (or derive from TextRendererBase<T>) and call MarkdownConverter.Convert(markdown, renderer, pipeline).

Roundtrip

When trivia tracking is enabled, the parser records all whitespace, line endings, and other characters that do not change the meaning of the document. The RoundtripRenderer then writes the document back exactly as it was parsed, so you can change a document without reformatting it.

using Meziantou.Framework.Markdown;
using Meziantou.Framework.Markdown.Renderers.Roundtrip;

var document = MarkdownConverter.Parse(markdown, trackTrivia: true);

// Change the tree here...

using var writer = new StringWriter();
var renderer = new RoundtripRenderer(writer);
renderer.Write(document);
var output = writer.ToString(); // Same as markdown when nothing changed

Trivia is not part of the CommonMark specification, so the implementation decides where it goes. Line endings are attached to the first node that can hold them. Blank lines are stored in Block.LinesBefore and Block.LinesAfter. Other properties are named Trivia* (for example TriviaBefore, TriviaAfter) on the blocks and inlines that need them. These properties are only populated when trivia tracking is enabled.

Differences from Markdig

  • The namespaces start with Meziantou.Framework.Markdown instead of Markdig.
  • The static Markdig.Markdown class is named MarkdownConverter, so it does not share its name with the namespace.
  • The package targets .NET 10 and later only. .NET Framework and .NET Standard are not supported.
  • HostProviderBuilder is a static class.
  • Generic attributes only write the attributes that describe the content by default (see Security). Markdig writes every attribute; pass _ => true as the filter of UseGenericAttributes to do the same.
  • The self pipeline extension (UseSelfPipeline) is removed: it let the Markdown document choose the extensions of the pipeline, including removing the ones that the host used to make the output safe.
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed.  net11.0 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.
  • net11.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 64 9/30/2026
1.0.0 190 9/28/2026