Skip to content

navara/md2html

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

md2html

Convert Markdown files to self-contained HTML — no external CSS, no external JS, optionally no external images. Six built-in themes, Pygments syntax highlighting, and a watch mode for live preview.

Features

  • CommonMark + GFM — tables, task lists, strikethrough, autolinks
  • Plus: footnotes, definition lists, heading anchors with slug ids
  • Twelve themes: minimal-light, minimal-dark, basic-light, basic-dark, github (auto light/dark via prefers-color-scheme), polished, solarized-light, solarized-dark, dracula, nord, gruvbox-dark, midnight
  • Syntax highlighting via Pygments (all 500+ supported languages)
  • Self-contained output: all CSS inlined; pass --inline-images to embed local images as base64 data URIs too
  • Configurable column width — sensible defaults per template, override with --width
  • Batch mode: point it at a directory and every .md becomes .html
  • Watch mode: re-render on save for live preview
  • Auto TOC: pass --toc to prepend a navigable table of contents

Install

From a checkout:

pip install -e .

Or with pipx to get an isolated CLI:

pipx install .

Requires Python 3.10+. Dependencies: markdown-it-py[linkify], mdit-py-plugins, Pygments, watchdog.

Usage

# Convert one file (output: doc.html next to doc.md)
md2html doc.md

# Choose a template
md2html doc.md -t github
md2html doc.md -t polished

# Send output somewhere else
md2html doc.md -o /tmp/out.html

# Convert every .md in a folder, output alongside sources
md2html ./docs

# Convert recursively into a mirrored output tree
md2html ./docs -r -o ./site -t github

# Add a table of contents
md2html doc.md --toc

# Replace an existing output (skip-existing is the default)
md2html doc.md --overwrite
md2html ./docs --overwrite          # regenerate the whole folder

# Embed local images as data URIs (truly portable)
md2html doc.md --inline-images

# Override column width (plain number = ch; unit accepted otherwise)
md2html doc.md --width 90          # 90ch
md2html doc.md --width 1200px      # explicit px
md2html doc.md --width 70rem       # rem also works

# Watch for changes and re-render
md2html doc.md --watch

# List available templates
md2html --list-templates

Or run as a module without installing the CLI shim:

python -m md2html doc.md -t github

Templates

Template Look Pygments style
minimal-light White, system sans, almost no chrome default
minimal-dark Near-black counterpart monokai
basic-light White with accent color, bordered tables and code friendly
basic-dark GitHub-ish dark counterpart dracula
github Faithful GH-README look, auto adapts to system theme github light/dark
polished Warm cream paper, serif body, sans headings, accents monokai
solarized-light The classic Solarized cream palette solarized-light
solarized-dark Solarized teal-dark counterpart solarized-dark
dracula Dracula — purple / pink / cyan on #282a36 dracula
nord Nord — frosty blues on cool slate nord
gruvbox-dark Warm yellow + brown on dark, retro Gruvbox look gruvbox-dark
midnight Deep navy with cyan/magenta neon glow on headings and code fruity

Most templates share a common stylesheet (_basic.css) and customize only the palette via CSS variables — adding a new theme is one file with ~10 lines. Templates with unique typography (minimal-*, github, polished) stand on their own.

All styles are scoped under main.md2html so embedding the rendered HTML into another page won't leak styles.

Column width

All templates default to a 1470px reading column (matching github) for visual consistency across themes. Pass --width to override:

md2html doc.md --width 80          # 80ch
md2html doc.md --width 1280px      # exact pixel width
md2html doc.md --width 60rem       # any CSS length unit works

Plain numbers are interpreted as ch (character widths). Anything else is passed through after a sanity check.

Programmatic use

from md2html import convert

html = convert(
    "# Hello\n\nSome **markdown**.",
    template="github",
    with_toc=True,
)

convert() returns the complete HTML document as a string.

Development

With uv (recommended)

uv sync                    # creates .venv, installs editable + locked dev deps
uv run pytest              # run tests
uv run md2html doc.md      # run the CLI without activating the venv
uv build                   # build wheel + sdist into dist/

uv.lock is committed so every contributor and CI run gets bit-identical transitive dependencies.

With stock pip / venv

py -m venv .venv
.venv\Scripts\python -m pip install -e . pytest build
.venv\Scripts\pytest
.venv\Scripts\python -m build

Tests live in tests/test_converter.py and exercise every template against the tests/fixtures/kitchen-sink.md document.

Out of scope

  • Custom CSS injection — fork or extend the template files instead
  • Mermaid / KaTeX rendering — they would require JS, breaking the self-contained guarantee
  • PDF output

License

MIT

About

Convert Markdown to self-contained HTML with themes and syntax highlighting

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors