Skip to content

The TMarkdownToHTML Component ​

TMarkdownToHTML

TMarkdownToHTML is a non-visual Delphi component that holds the options of the Markdown Processor and converts its Markdown content into HTML. Every time the content or an option changes, the HTML is rebuilt automatically, so the component can be configured at design time in the Object Inspector and used with a single line of code at runtime.

The component is available from version 2.0.0 in the unit MarkdownProcessorComponents.pas (runtime package MarkdownProcessor) and it is registered by the design-time package dclMarkdownProcessor in the Markdown page of the Tool Palette. The names of the properties are the same as the ones of the TMarkdownViewer component of the MarkdownHelpViewer project.

Quick start ​

Drop a TMarkdownToHTML on a form (or create it in code), assign the Markdown and read the HTML:

Pascal
uses
  MarkdownUtils, MarkdownProcessorComponents;

procedure TMainForm.ShowHTML;
begin
  MarkdownToHTML.MarkdownContent.Text := '# Hello' + sLineBreak + 'Some **Markdown** text';
  HTMLMemo.Lines.Text := MarkdownToHTML.HtmlContent.Text;
end;

Creating it in code:

Pascal
var
  LConverter: TMarkdownToHTML;
begin
  LConverter := TMarkdownToHTML.Create(nil);
  try
    LConverter.CssStyle.Clear;                 // only the HTML fragment
    LConverter.ProcessorDialect := mdGFM;      // resets Extensions to the GFM defaults
    LConverter.Extensions := LConverter.Extensions - [mexSmartTypography];
    LConverter.FileName := 'Readme.md';        // loads and converts the file
    LConverter.ExportToFileHTML('Readme.html');
  finally
    LConverter.Free;
  end;
end;

Default options ​

A new component converts with the default dialect, GitHub, in safe mode, and writes the default stylesheet before the HTML. Besides the extensions of the dialect, the component enables by default all the legacy extensions of the Markdown Processor (constant LegacyExtensions): they act only on their own syntax, so they do not change a document that does not use it.

DialectDefault Extensions of the component
mdGitHub (default)GitHubExtensions (tables, task lists, strikethrough, autolinks, tag filter, math, alerts, mermaid) + LegacyExtensions
mdGFMGFMExtensions (tables, task lists, strikethrough, autolinks, tag filter) + LegacyExtensions
mdCommonMarkLegacyExtensions
mdDaringFireball, mdTxtMarknone: the legacy dialects ignore the extensions

LegacyExtensions = [mexSubscript, mexSuperscript, mexInsert, mexMark, mexSmartTypography, mexHeadingAttributes, mexAutoHeadingIds, mexWikiLinks]: H~2~O, x^2^, ++inserted++, ==marked==, smart typography (--, ---, ..., (C), curly quotes, guillemets), # Title {#id}, GitHub-style heading ids and [[wiki links]]. See Extensions for the complete list of the flags.

Changing ProcessorDialect always resets Extensions to the defaults of the new dialect: set the dialect first, then add or remove the extensions. In the form file Extensions is stored only when it differs from the defaults of the dialect.

Published properties ​

PropertyTypeDefaultDescription
ProcessorDialectTMarkdownProcessorDialectmdGitHubThe Markdown dialect: mdGitHub, mdGFM, mdCommonMark, mdDaringFireball, mdTxtMark. Changing it resets Extensions.
ExtensionsTMarkdownExtensionsDefaultExtensions(ProcessorDialect)The optional syntax of the new engine (GitHub, GFM, CommonMark); ignored by the legacy dialects.
AllowUnsafeBooleanFalseWhen True, raw HTML (script, iframe...) and every link are kept as they are: use it only with trusted content. With False raw HTML is omitted and dangerous links are emptied.
MathRenderingTMarkdownMathRenderingmmrMarkupmmrMarkup: markup for KaTeX/MathJax (viewers with JavaScript, e.g. WebView2); mmrCodeCogsImage: every formula is an image, for viewers without JavaScript (e.g. HTMLViewer).
CssStyleTStringListMarkdownDefaultCSSThe stylesheet written before the HTML fragment in HtmlContent. Clear it to get the bare fragment. Stored only when it differs from the default.
FileNameTFileNameAssigning the name of an existing file loads it (see LoadFromFile).
MarkdownContentTStringListThe Markdown source: every change converts it again.
HtmlContentTStringListThe result: CssStyle followed by the HTML fragment. It can also be assigned directly (for example to show an HTML file): when MarkdownContent is empty it is kept as it is.
OnChangeTNotifyEventFired after HtmlContent changes.

Public properties ​

PropertyTypeDescription
CodeBlockEmitterTBlockEmitterWhen assigned, receives every code block (fenced and indented, mermaid included) with its lines and its info string, and writes the HTML of the block: use it for syntax highlighting. Not owned by the component.
SpecialLinkEmitterTSpanEmitterWith mexWikiLinks, receives the content of every [[...]] link and writes its HTML; without it the link is written as text. Not owned by the component.

Unlike TMarkdownProcessor.Config, the component does not free the emitters assigned to it: the application creates them and frees them (after detaching them, or after freeing the component).

Pascal
type
  // [[Page name]] -> <a href="Page%20name.md">Page name</a>
  TWikiLinkEmitter = class(TSpanEmitter)
  public
    procedure emitSpan(out_: TStringBuilder; content: String); override;
  end;

procedure TWikiLinkEmitter.emitSpan(out_: TStringBuilder; content: String);
begin
  out_.Append('<a href="' + StringReplace(content, ' ', '%20', [rfReplaceAll]) +
    '.md">' + content + '</a>');
end;

// FormCreate
FWikiLinkEmitter := TWikiLinkEmitter.Create;
MarkdownToHTML.SpecialLinkEmitter := FWikiLinkEmitter;

// FormDestroy
MarkdownToHTML.SpecialLinkEmitter := nil;
FWikiLinkEmitter.Free;

Methods ​

MethodDescription
procedure UpdateHTMLConverts MarkdownContent again into HtmlContent and fires OnChange. It is called automatically when the content or an option changes; nothing happens when MarkdownContent is empty.
procedure LoadFromFile(const AFileName: TFileName)Loads a file: .htm/.html files go to HtmlContent, any other file to MarkdownContent (and it is converted). The encoding is detected as in TryLoadTextFile.
procedure LoadFromStream(const AStream: TStringStream; const IsHTMLContent: Boolean = False)Loads the text of a stream as Markdown, or as HTML when IsHTMLContent is True.
procedure LoadFromString(const AValue: string; const IsHTMLContent: Boolean = False)Loads a string as Markdown (converted once), or as HTML.
procedure ExportToFileHTML(const AFileName: TFileName)Saves HtmlContent to a UTF-8 file.
function TransformContent(const AMarkdownContent: string): stringConverts a Markdown text with the options of the component and returns CssStyle followed by the HTML fragment, without changing MarkdownContent and HtmlContent.
function TransformContent(const AMarkdownContent: string; AProcessorDialect: TMarkdownProcessorDialect; const ACssStyle: string = ''; const AAllowUnsafe: Boolean = False): stringConverts a Markdown text with the given dialect (with the extensions of the dialect in the library), stylesheet and safe mode, as TMarkdownViewer.TransformContent.
class function DefaultExtensions(const ADialect: TMarkdownProcessorDialect): TMarkdownExtensionsThe default extensions of the component for a dialect (see Default options).
function CreateProcessor: TMarkdownProcessor (protected, virtual)Creates the TMarkdownProcessor with the options of the component: override it in a descendant of TCustomMarkdownToHTML to configure the processor further.

Utility functions ​

The unit MarkdownProcessorComponents.pas also exposes:

FunctionDescription
function TryLoadTextFile(const AFileName: TFileName): stringLoads a text file: the BOM, when present, decides the encoding; otherwise UTF-8 if the bytes are valid UTF-8, else ANSI.
procedure SaveUTF8File(const AFileName: TFileName; const AContent: string)Saves a string to a UTF-8 file.
function GetMarkdownDefaultCSS: stringThe default stylesheet (MarkdownDefaultCSS).

Showing the HTML ​

HtmlContent is an HTML fragment preceded by the stylesheet, not a full page. To show it in a browser or in WebView2, put it in a page; when the document contains math formulas or mermaid diagrams (GitHub dialect), the page must also load KaTeX and mermaid.js, as the Demo does:

html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/contrib/auto-render.min.js"
  onload="renderMathInElement(document.body);"></script>
<script type="module">
  import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
  mermaid.initialize({ startOnLoad: true });
</script>

For a viewer without JavaScript (e.g. HTMLViewer) set MathRendering := mmrCodeCogsImage: the formulas become images, while mermaid diagrams show their source text.

Released under Apache License, Version 2.0.