Pandoc is a very handy tool to create PDF documents from MarkDown files.

Its workflow is very similar to LaTeX (and indeed, by default, it uses it to convert to PDF), but less verbose and a bit easier to write.

However, soon you will face the limits of MarkDown, such as the lack of colors, and you’ll start to introduce bad LaTeX code for this or that feature.

Let’s see a better way to solve the problem.

LUA filters

Pandoc supports LUA filters as preprocessor for the documents: with them you can create custom elements that will change various aspects of the document.

You just need to put the .lua script in your document’s folder, and pass the --lua-filter=filter.lua option to the Pandoc command line.

A complete guide to write LUA filters for Pandoc can be found here.


MarkDown doesn’t support colors. Our LUA filter would parse for a particular keyword (e.g. color), and insert the LaTeX command. The script below also converts colors for HTML documents.

Span = function(el)
  color = el.attributes['color']
  -- if no color attribute, return unchanged
  if color == nil then return el end
  -- transform to <span style="color: red;"></span>
  if FORMAT:match 'html' then
    -- remove color attributes
    el.attributes['color'] = nil
    -- use style attribute instead
    el.attributes['style'] = 'color: ' .. color .. ';'
    -- return full span element
    return el
  elseif FORMAT:match 'latex' then
    -- remove color attributes
    el.attributes['color'] = nil
    -- encapsulate in latex code
      el.content, 1,
      pandoc.RawInline('latex', '\\textcolor{'..color..'}{')
      pandoc.RawInline('latex', '}')
    return el.content
    -- for other format return unchanged
    return el

You also have to include the directive \usepackage{xcolor} in your document.

To do this, either create a style.tex file with the above instruction, included with -H style.tex option, or by adding the following in your frontmatter:

header-includes: |

Then, colore your text with [your text here]{color="red"].

Quotes and colored blocks

Sometimes you want to highlight some part of your text (e.g. warnings or solutions blocks).

In LaTeX you would use tcolorbox. And you may use it also in Pandoc, but it will break any other non-LaTeX output. Let’s create another LUA filter for this purpose.

function Div(el)

  if el.classes[1] == "warning"
  or el.classes[1] == "suggestion"
    -- insert element in front
      el.content, 1,
      pandoc.RawBlock("latex", "\\begin{quote_" .. el.classes[1] .. "}"))
    -- insert element at the back
      pandoc.RawBlock("latex", "\\end{quote_" .. el.classes[1] .. "}"))
  return el

Then declare each class in your style.tex:


% New tcolorbox
\newtcolorbox{warning}{colback=red!5!white, colframe=red!50!white, title={Warning},fonttitle=\bfseries}
\newtcolorbox{suggestion}{colback=green!5!white, colframe=green!50!black, title={Suggestion},fonttitle=\bfseries,}

% Declare the environments

Then use it as:

::: warning

Your very important text.

With **any**** Markdown __style____.


More intelligent titles

Wondering how to reduce the space above title on the first page and make things a bit more compact? Paste this in your style.tex file:


To change the geometry, add this:

\usepackage[margin=2cm,top=2.5cm, bottom=2.5cm]{geometry}

You can also add the same directives to the frontmatter, but having a separate .tex style file allows for multiples styles just by changing the command line.

If the weight of section titles isn’t enough:


Section numbering

Add --number-sections to have numbered sections (e.g. each section will be preceded by its number.


Use --listings to set Pandoc to use the listings package to generate code listings. You can then set any additional settings as normal LaTeX documents in style.tex.

Page format

Is Pandoc producing a Letter document? Use -V papersize:a4 to set to the european standard format A4, or to any other you want.


Wouldn’t it be great to not remember the super-long command line? Make to the rescue!

PANDOC=$(shell which pandoc)
OPTS=--lua-filter=quote_filter.lua --number-sections --listings  -V papersize:a4
DEPS=style.tex Makefile
DEPS+=$(wildcard *.lua)

%.pdf: $(DEPS)
	$(PANDOC) $< -o $@ -H $(HEADERS) $(OPTS)

Now just type make to have your PDF compiled.

Continuous compilation

Are you fixing a document and continuing to switch between your markdown, terminal and viewer?

Through make your document is recompiled only when the source files change.

So you can run watch -n 1 make, which will automatically re-compile the document when needed.