markdown

Overview

Fantom library for parsing and rendering Markdown text according to the CommonMark specification.

Usage

using markdown

parser := Parser()
doc := parser.parse("This is *Markdown*")
renderer := HtmlRenderer()
html := renderer.render(doc) // => "<p>This is <em>Markdown</em></p>\n"

This uses the parser and renderer with default options. Both have builders for configuring their behavior. See ParserBuilder and HtmlRendererBuilder for more details.

Use a visitor to process parsed nodes

After the source text has been parsed, the result is a tree of nodes. That tree can be modified before rendering, or just inspected without rendering. See Visitor and the HTML rendering example below.

HTML Rendering

You can take complete control over how HTML is rendered.

In this example, we're changing the rendering of indented code blocks to only wrap them in pre instead of pre and code:

parser := Parser()
renderer := HtmlRenderer.builder
  .nodeRendererFactory(|HtmlContext cx->NodeRenderer| { IndentedCodeBlockRendere(cx) })
  .build
html := renderer.render(parser.parse("Example:\n\n    code"))
// "<p>Example:</p><pre>code</pre>\n"

class IndentedCodeBlockRenderer : NodeRenderer, Visitor
{
  new make(HtmlContext cx) { this.html = cx.writer }
  private HtmlWriter html

  ** We only want to override rendering of the Code node type
  override const Type nodeTypes := [Code#]

  override Void render(Node node) { node.walk(this) }

  override Void visitIndentedCode(IndentedCode code)
  {
    html.line
      .tag("pre")
      .text(code.literal)
      .tag("/pre")
      .line
  }
}

Add your own node types

In case you want to store additional data in the document, or have custom elements in the resulting HTML, you can create your own subclass of CustomNode or CustomBlock and add instances as child nodes to existing nodes.

To define the HTML rendering for them, you can use a NodeRenderer as explained above.

Plaintext Rendering

You can also render markdown to plaintext with most formatting removed. The builder for the TextRenderer supports various methods or rendering line breaks depending on your use case.

// Generate plaintext using the default "compact" rendering
doc := Parser().parse("Here, the **emphasis** is ignored")
str := TextRenderer().render(doc) // => Here the emphasis is ignored

Customize parsing

There are a few ways to extend parsing or even override built-in parsing, all of them via methods on Parser.builder. See Section 3 (Blocks and Inlines) of the spec for an overview of blocks/inlines.

  • Parsing of specific block types (e.g. headings, code blocks, etc.) can be enabled/disabled with withEnabledBlockTypes
  • Parsing of blocks can be extended/overridden with customBlockParserFactory
  • Parsing of inline content can be extended/overridden with customInlineContentParserFactory
  • Processing of links can be customized with linkProcessor and linkMarker

Thread-safety

Both the Parser and the HtmlRenderer are designed so that you can configure them once and then use them multiple times/from multiple Actors.

Extensions

Extensions are used to extend the parser, the HTML renderer, or both. Extensions are configured on the various builders using the extensions() method. The default parser and HTML renderer conform to the CommonMark specification. This library includes some built-in extensions that you can optionally enable.

For example, the following code enables the ImgAttrsExt which allows you to specify attributes for images.

using markdown

exts := [ImgAttrsExt()]
parser := Parser.builder.extensions(exts).build
renderer := HtmlRenderer.builder.extensions(exts).build

Image Attributes

Adds support for specifying attributes (specifically height and width) for images. Use ImgAttrsExt to enable this extension.

The attribute elements are given as key=value pairs inside curly braces { } after the image node to which they apply. For example:

![text](/url.png){width=640 height=480}

will be rendered as

<img src="/url.png" alt="text" width="640" height="480" />

Tables

Enables tables using pipes as in Github Flavored Markdown. See TablesExt.

| Header1 | Header2 |
| ------- | ------- |
| foo     | bar     |

Haxall 4.0.5 ∙ 24-Feb-2026 14:33 EST