Curtis O'Donnell - Web Developer Skip to main content

Preview

5 min read

Preview Any Document: Multi-Format HTML with Dark/Light Mode

If you work a lot in the terminal and write a lot of markdown specs, LaTeX, or other markup formats, you know how convenient it is to quickly see a rendered version of your work. Here’s a nice tool to do this within a terminal.

Why This Matters

Writers, developers, and researchers often deal with multiple file formats:

  • Markdown (.md) for notes or blogs
  • LaTeX (.tex) for academic papers
  • ReStructuredText (.rst) for documentation
  • AsciiDoc (.adoc) or Org-mode (.org) for project notes
  • HTML for raw web content

Switching between editors, browsers, and PDF exporters can be tedious. The goal is simple: write once, preview everywhere, instantly.

Requirements

Make sure Pandoc is installed:

sudo pacman -S pandoc

Save your dark/light templates somewhere (e.g., ~/.pandoc/templates/professional-dark.html) Some example templates are at the end.

Set environment variables:

export PREVIEW_DARK_TEMPLATE_FILE="$HOME/.pandoc/templates/professional-dark.html"
export PREVIEW_LIGHT_TEMPLATE_FILE="$HOME/.pandoc/templates/professional-light.html"

Add the preview function to your .bashrc or .zshrc

And you’re ready to preview any document, anytime.

preview function

## takes a file for input and opens the styled html output in a browser with xdg-open
preview() {
  if [[ $# -lt 1 ]]; then
    echo "Usage: mdpreview [-d|-l] <file1.md> [file2.md ...]"
    echo "  -d  dark mode (default)"
    echo "  -l  light mode"
    return 1
  fi

  local mode="dark"
  local files=()

  # check for mode flag
  if [[ "$1" == "-d" ]]; then
    mode="dark"
    shift
  elif [[ "$1" == "-l" ]]; then
    mode="light"
    shift
  fi

  if [[ $# -lt 1 ]]; then
    echo "No Markdown files provided."
    return 1
  fi

  local template_file
  if [[ "$mode" == "dark" ]]; then
    template_file="${MARKDOWN_DARK_TEMPLATE_FILE:-$HOME/.pandoc/templates/professional-dark.html}"
  else
    template_file="${MARKDOWN_LIGHT_TEMPLATE_FILE:-$HOME/.pandoc/templates/professional-light.html}"
  fi

  for input in "$@"; do
    if [[ ! -f "$input" ]]; then
      echo "File not found: $input"
      continue
    fi

    local filename=$(basename "$input")
    local name="${filename%.md}"
    local output="/tmp/${name}.html"

    pandoc --standalone \
           --metadata title="$name" \
           --template="$template_file" \
           "$input" > "$output" || { echo "Failed: $input"; continue; }

    echo "Opened: $output"
    xdg-open "$output"
  done
}

This shell function lets you:

  1. Open one or multiple files at once
  2. Automatically generate an HTML file in /tmp
  3. Use dark or light mode templates for readability

Usage

# Preview a single file (dark mode by default)
preview my_notes.md

# Preview multiple files
preview chapter1.md chapter2.md chapter3.md

# Use light mode
preview -l chapter1.md chapter2.md

What’s Under the Hood

The function uses Pandoc, combined with custom HTML templates. The templates include:

  • A constrained width wrapper for comfortable reading
  • Consistent typography for headings, paragraphs, lists, code blocks, tables, and blockquotes
  • Dark/light color schemes for eye comfort
  • Syntax highlighting for code snippets

Multi-Format Support

Because Pandoc supports dozens of formats, you can preview almost anything:

  • Markdown (.md)
  • ReStructuredText (.rst)
  • AsciiDoc (.adoc)
  • Org-mode (.org)
  • HTML (.html)
  • LaTeX (.tex)

Templates

  • Dark
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>$title$</title>
  <style>
  /* ================================
     Dark Mode Styles
     ================================ */

  :root {
    --bg: #1f2328;
    --surface: #24292f;
    --border: #30363d;
    --text: #e6edf3;
    --text-muted: #9da7b3;
    --heading: #f0f6fc;
    --accent: #4ea1ff;
    --code-bg: #2b3137;
    --quote-border: #3b434b;
    --radius: 6px;
  }

  html { font-size: 16px; }
  body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    line-height: 1.7;
  }

  .doc-wrapper {
    display: flex;
    justify-content: center;
    padding: 3rem 1.5rem 4rem;
  }
  .doc { width: 100%; max-width: 780px; }

  p, ul, ol, blockquote, pre, table { margin-bottom: 1.6rem; }
  h1, h2, h3, h4, h5, h6 {
    margin-top: 2.4rem;
    margin-bottom: 0.8rem;
    font-weight: 600;
    color: var(--heading);
    line-height: 1.3;
  }
  h1, h2 { border-bottom: 1px solid var(--border); padding-bottom: 0.4rem; }

  a { color: var(--accent); text-decoration: none; }
  a:hover { text-decoration: underline; }

  blockquote {
    padding: 0.8rem 1rem;
    border-left: 4px solid var(--quote-border);
    background: var(--surface);
    border-radius: var(--radius);
    color: var(--text-muted);
  }

  code {
    font-family: ui-monospace, monospace;
    background: var(--code-bg);
    padding: 0.2em 0.4em;
    border-radius: 4px;
    font-size: 0.9em;
  }

  pre {
    background: var(--code-bg);
    padding: 1rem;
    border-radius: var(--radius);
    overflow-x: auto;
  }

  table { width: 100%; border-collapse: collapse; }
  th, td { padding: 0.6rem 0.8rem; border-bottom: 1px solid var(--border); }
  th { text-align: left; font-weight: 600; color: var(--heading); }
  tr:last-child td { border-bottom: none; }

  hr { border: 0; border-top: 1px solid var(--border); margin: 2.5rem 0; }

  strong { font-weight: 600; color: var(--heading); }
  em { font-style: italic; color: #d2dbe3; }

  img { max-width: 100%; height: auto; border-radius: var(--radius); display: block; margin: 1.6rem 0; }

  ::selection { background: rgba(78, 161, 255, 0.35); }

  $if(highlighting-css)$
  $highlighting-css$
  $endif$
  </style>
</head>
<body>
  <div class="doc-wrapper">
    <article class="doc">
      $body$
    </article>
  </div>
</body>
</html>
  • Light
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>$title$</title>
  <style>
  /* ================================
     Light Mode Styles
     ================================ */

  :root {
    --bg: #fafbfc;
    --surface: #ffffff;
    --border: #d0d7de;
    --text: #24292f;
    --text-muted: #57606a;
    --heading: #111827;
    --accent: #0366d6;
    --code-bg: #f6f8fa;
    --quote-border: #d0d7de;
    --radius: 6px;
  }

  html { font-size: 16px; }
  body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    line-height: 1.7;
  }

  .doc-wrapper {
    display: flex;
    justify-content: center;
    padding: 3rem 1.5rem 4rem;
  }
  .doc { width: 100%; max-width: 780px; }

  p, ul, ol, blockquote, pre, table { margin-bottom: 1.6rem; }
  h1, h2, h3, h4, h5, h6 {
    margin-top: 2.4rem;
    margin-bottom: 0.8rem;
    font-weight: 600;
    color: var(--heading);
    line-height: 1.3;
  }
  h1, h2 { border-bottom: 1px solid var(--border); padding-bottom: 0.4rem; }

  a { color: var(--accent); text-decoration: none; }
  a:hover { text-decoration: underline; }

  blockquote {
    padding: 0.8rem 1rem;
    border-left: 4px solid var(--quote-border);
    background: var(--surface);
    border-radius: var(--radius);
    color: var(--text-muted);
  }

  code {
    font-family: ui-monospace, monospace;
    background: var(--code-bg);
    padding: 0.2em 0.4em;
    border-radius: 4px;
    font-size: 0.9em;
  }

  pre {
    background: var(--code-bg);
    padding: 1rem;
    border-radius: var(--radius);
    overflow-x: auto;
  }

  table { width: 100%; border-collapse: collapse; }
  th, td { padding: 0.6rem 0.8rem; border-bottom: 1px solid var(--border); }
  th { text-align: left; font-weight: 600; color: var(--heading); }
  tr:last-child td { border-bottom: none; }

  hr { border: 0; border-top: 1px solid var(--border); margin: 2.5rem 0; }

  strong { font-weight: 600; color: var(--heading); }
  em { font-style: italic; color: #333; }

  img { max-width: 100%; height: auto; border-radius: var(--radius); display: block; margin: 1.6rem 0; }

  ::selection { background: rgba(3, 102, 214, 0.25); }

  $if(highlighting-css)$
  $highlighting-css$
  $endif$
  </style>
</head>
<body>
  <div class="doc-wrapper">
    <article class="doc">
      $body$
    </article>
  </div>
</body>
</html>

Get In Touch

Have a project in mind or want to collaborate? I'd love to hear from you. Send me a message and I'll get back to you as soon as possible.

* Required fields

Or reach out directly: