MarkdownControl renders markdown using Markdig and displays the result through DocumentFlow.
It lives in the extension package:
dotnet add package XenoAtom.Terminal.UI.Extensions.Markdown

using XenoAtom.Terminal.UI.Controls;
using XenoAtom.Terminal.UI.Extensions.Markdown;
var markdown = """
# Title
Paragraph with **strong** text and a [link](https://example.com).
""";
var control = new MarkdownControl(markdown);
MarkdownControl disables DocumentFlow follow-tail by default so documents open from the top.
MarkdownControl uses a default pipeline supporting CommonMark plus tables and alert blocks.
You can provide your own pipeline and rendering options:
using Markdig;
using XenoAtom.Terminal.UI.Extensions.Markdown;
var pipeline = new MarkdownPipelineBuilder()
.Configure("common+pipetables+alerts+tasklists")
.Build();
var control = new MarkdownControl(markdown)
{
Pipeline = pipeline,
BaseUri = new Uri("https://xenoatom.github.io/terminal/docs/"),
Options = MarkdownRenderOptions.Default with
{
WrapCodeBlocks = false,
MaxCodeBlockHeight = 14,
HeadingSpacingBefore = 0,
HeadingSpacingAfter = 1,
ParagraphSpacing = 1,
BlockSpacing = 1,
}
};
For Markdown documents that contain local file links, use LocalFileRootPath to resolve relative paths into valid local file:// URIs:
var control = new MarkdownControl(markdown)
{
Options = MarkdownRenderOptions.Default with
{
LocalFileRootPath = Environment.CurrentDirectory,
}
};
Absolute local paths such as C:\docs\guide.md on Windows are also normalized to file:// links automatically.
Spacing defaults are intentionally compact for terminal density:
0111MarkdownControl exposes a code-block extension point through MarkdownRenderOptions.CodeBlockRenderer.
This lets you replace the default plain LogControl rendering for fenced or indented code blocks:
public sealed class MyCodeBlockRenderer : IMarkdownCodeBlockRenderer
{
public Visual? CreateVisual(in MarkdownCodeBlockRenderContext context)
{
if (!string.Equals(context.Language, "demo", StringComparison.OrdinalIgnoreCase))
{
return null; // fall back to the built-in renderer
}
return new TextBlock("custom renderer");
}
}
var control = new MarkdownControl(markdown)
{
Options = MarkdownRenderOptions.Default with
{
CodeBlockRenderer = new MyCodeBlockRenderer(),
},
};
Returning null delegates back to the built-in Markdown code-block visual.
To syntax-highlight fenced code blocks with bundled TextMate grammars and themes, install the companion package:
dotnet add package XenoAtom.Terminal.UI.Extensions.CodeEditor.TextMateSharp
Then configure the Markdown renderer:
using XenoAtom.Terminal.UI.Extensions.CodeEditor.TextMateSharp;
var control = new MarkdownControl(markdown)
{
Options = MarkdownRenderOptions.Default with
{
CodeBlockRenderer = new TextMateMarkdownCodeBlockRenderer(),
WrapCodeBlocks = false,
},
};
The TextMate-backed renderer understands fenced language identifiers such as csharp, json, or markdown, and it
automatically selects bundled light or dark TextMate themes to match the active terminal UI theme.
Use RenderStyle for role-based customization (headings, links, emphasis, alerts):
using XenoAtom.Terminal.UI.Extensions.Markdown.Styling;
var control = new MarkdownControl(markdown)
{
RenderStyle = MarkdownStyle.Default with
{
LinkStyle = Style.None | TextStyle.Bold | TextStyle.Underline,
Heading1Style = Style.None | TextStyle.Bold | TextStyle.Underline
}
};
By default, MarkdownControl applies a theme-aware style profile:
NOTE/TIP/IMPORTANT/WARNING/CAUTION) map to semantic theme tones (primary/success/accent/warning/error)