Blogdown: A markdown-like markup language designed for blog posts

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]


A library and executable that implement a modified, extended version of Markdown designed for writing blog posts.

[Skip to Readme]


Versions 0.1.0, 0.2.0, 0.2.1, 0.2.2, 0.2.2, 0.2.3, 0.2.4
Change log
Dependencies base (>=4.9 && <4.10), containers (>=0.5 && <0.6), MissingH (>=1.4 && <1.5), network-uri (>=2.6 && <2.7), parsec (>=3.1 && <3.2) [details]
License AGPL-3.0-only
Copyright (c) 2017 Alex Becker
Author Alex Becker
Category Web
Home page
Source repo head: git clone
Uploaded by alexbecker at 2017-05-22T16:20:16Z




Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Readme for Blogdown-0.2.2

[back to package description]

Note: If you are viewing this Readme on GitHub, its Blogdown-specific features will not render correctly. The Blogdown-formatted output is in test/goldens/Readme.html.


Blogdown is a markup language based on Markdown, designed for writing blog posts. Blogdown's goals are:

Because there is no Markdown standard and existing Markdown implementations disagree wildly even on simple cases, Blogdown cannot be 100% compatible with even a majority of Markdown implementations. While there have been attemps to create a common Markdown standard--most notably CommonMark--they are necessarily quite complex. The primary cause of this complexity is that Markdown insists on rendering something for every input, no matter how malformed. Blogdown is considerably simpler, and hopefully easier for authors to debug, because it fails on malformed inputs. With full compatability out of the window, I have chosen to make some other small improvements on Markdown syntax.


With Cabal or Stack

The recommended way to install any Haskell project is using Cabal or Stack. With these tools, you can simply run cabal install or stack build respectively.

Without Haskell Tooling

Because configuring Cabal and Stack can be tricky for Haskell beginners, Blogdown supports installation without any Haskell tooling.

First, install GHC, Parsec and MissingH, all of which are available through common Linux package managers. To compile static assets into Haskell files, run ghci Setup.hs and manually invoke compileStaticFiles. Then run ghc -isrc -iassets -o Blogdown src/Blogdown.hs in the repository's base directory.


The Blogdown binary reads from stdin and writes to stdout. Typical usage looks like:

cat | ./Blogdown > blogpost.html

Optional Styling and Scripts

It is recommended to include footnotes.css and footnotes.js on any pages which make use of Blogdown-generated footnotes, which improve the appearance of footnotes and allow them to be shown inline. These can be inlined using the --inline-css and --inline-js flags respectively^[inline].

Optional Flags

Blogdown accepts the following long-style flags:


Differences from Markdown

Most of the syntax of Blogdown should be familiar to Markdown users, but some new syntax has been added, and some existing syntax has changed.

New Features

Blogdown adds footnote support to Markdown. Footnotes can be referenced inline with ^[footnote-name], which will render as a superscript link to a footnote-definition at the end of the document, which is defined by ~[footnote-name] followed by the footnote contents.

Markdown Incompatibilities

Blogdown does not support the Markdown syntax of underlining text with = or - characters to define a header, as this comes at a large cost in the parser implementation^[underline-parser-complexity]. The # syntax for headers is supported instead.

It also does not support using multiple trailing spaces to force a breakpoint at the end of a line. The <br/> tag is supported instead.

While tables are not a feature of base Markdown, some common Markdown implementations such as Github Flavored Markdown support them. Blogdown also supports tables, but its implementation is slightly different from Github's, requiring | characters at the start and end of a row and using + instead of | in the separator between the (optional) table header and table body.

Since Blogdown introduces new syntax, some valid Markdown will require escaping to render as expected in Blogdown. Additionally, while most Markdown implementations do not require escaping many special characters when their special meaning would not be valid, Blogdown always requires they be escaped.

HTML Embedding

Like most Markdown implementations, Blogdown documents can have HTML embedded inside them. However, Blogdown allows only a limited subset of HTML, specifically XHTML, with the exceptions that unknown tags are permitted, and that any tag is allowed to be self-closing^[arbitrary-tags]. By default Blogdown will not allow <script> or <style> tags, since parsing for these is very complex and not fully implemented. However, when parsing trusted content it is generally safe to use --allow-unsafe-tags to attempt to allow these anyway.

Note also that any content within an HTML node is rendered verbatim, so Blogdown features cannot be used inside HTML nodes.

HTML Bleaching

If using Blogdown to parse untrusted content (such as comments on a blog), the --allowed-tags and --allowed-attributes flags must be used to restrict what HTML can be rendered in the output. Generally these flags should be used without without arguments, bleaching all HTML. If you must allow some HTML, you should only allow tags and attributes which are necessary for your use case and which you understand the security implications of.

The --allow-unsafe-tags must not with untrusted content.

Formal Description

The body of a Blogdown document consists of a sequence of block nodes, which in turn consist of inline nodes.

Block Nodes

Block nodes can contain any sequence of inline nodes, with the exception of code and HTML blocks, whose contents are rendered verbatim. Block nodes can span multiple lines and are terminated by a blank line, the beginning of another type of block, or the end of the document.

The following block node types are supported:

The cells are themselves blocks, and as such can contain newlines. The rows are terminated by a | followed by a newline. By default the table has only a body, but if rows are separated by an alternating string of + and multiple - characters, e.g. +---+---+, then every row above the separator will be in the header and every row below will be in the body. Optionally the table may start and end with such a separator as well.

Inline Nodes

Inline nodes can generally contain a sequence of other inline nodes, but cannot contain nodes of the same type. Despite the name, inline nodes can span multiple lines, e.g. to accommodate line length limits.

The following inline node types are supported:

A Blogdown document may optionally include a footer after the body. The footer consists of a sequence of footnote definitions, each of which begins on a new line with ~[footnote-name] and consists of an arbitrary sequence of blocks. A footnote definition is only terminated by another footnote definition or the end of the document.


Any character (special or not) can be escaped with \\. For a literal backslash, use \\\\. A backslash before a newline acts as a continuation character.

Planned improvements

~[inline] Inlining CSS and JS is not recommended if you will be rendering multiple Blogdown documents on a single page, e.g. multiple blog posts on a blog. Doing so will degrade network and browser performance slightly.

~[underline-parser-complexity] Supporting underlines for headers requires the parser to look-ahead arbitrarily far, resulting in quadratic time complexity.

~[arbitrary-tags] Arbitrary tags are allowed for ease of implementation, although they are also potentially useful, e.g. for Angular support.

~[footnote-numbering] Footnotes are auto-numbered in order of appearance, starting from 0 by default (this can be changed by passing the --footnote-index-from flag).