Skip to content

markwright

markwright is a set of Python-Markdown extensions plus a companion CLI, mw, for author-friendly markdown: highlighted text, labeled code fences, and media embeds. Use the extensions in any tool built on Python-Markdown (including MkDocs), or the mw pipeline in toolchains that are not, like Hugo.

The author-facing syntax and HTML output are derived from DigitalOcean's do-markdownit (licensed under the Apache License 2.0); markwright ports those to Python-Markdown and adds the mw CLI on top. See NOTICE for attribution.

Features

  • Highlight wraps <^>text<^> in <mark>, and works inside inline code and fenced code blocks where ==text== cannot reach.
  • Fence adds labels, secondary labels, environment classes, and command-line prefixes to code blocks.
  • YouTube turns [youtube ID] into a responsive iframe embed.
  • CodePen embeds a pen with theme, default-tab, and layout options.
  • Twitter embeds a tweet with theme and alignment options.
  • Instagram embeds a post with caption and alignment options.
  • Slideshow builds an image slideshow with navigation arrows.
  • Image Compare renders two images with a draggable before/after slider.

Installation

uv add markwright

Or install from a local path:

uv add --editable ../markwright

MkDocs 2.0 Compatibility

MkDocs 2.0 removes the plugin system and rewrites the theming architecture, breaking all existing plugins and themes including Material for MkDocs. There is no migration path. This project pins MkDocs 1.x (mkdocs>=1.6,<2).

Usage

These extensions work with Python-Markdown directly, so you can use them in any Python program (a Flask app, a CLI tool, a static site generator, or a simple script).

import markdown

md = markdown.Markdown(
    extensions=[
        "pymdownx.superfences",
        "pymdownx.highlight",
        "markwright.highlight",
        "markwright.fence",
        "markwright.youtube",
        "markwright.codepen",
        "markwright.twitter",
        "markwright.instagram",
        "markwright.slideshow",
        "markwright.image_compare",
    ]
)

source = """
```command
[label deploy.sh]
ssh root@server
apt update
```
"""

html = md.convert(source)
print(html)

You can also load only the extensions you need by listing just those in the extensions list.

Using MkDocs? See Using with MkDocs for the mkdocs.yml configuration.

Note

The fence extension should be used alongside pymdownx.superfences and pymdownx.highlight for proper code block rendering. Without them, the fence preprocessor will still extract directives, but the code block HTML structure may differ from what the postprocessor expects.

Using It Outside Python

If your toolchain is not built on Python-Markdown, the mw command-line tool runs the same extensions as pre and post filters around any renderer:

mw pre < in.md | your-renderer | mw post > out.html

See the CLI Reference for the commands and flags, and the Hugo integration guide for a worked setup.

Architecture

Each extension is a standalone Python-Markdown extension loaded by name (e.g., markwright.highlight). The extensions use three processor patterns:

  1. Fence uses a Preprocessor (priority 40) that runs before pymdownx.superfences to extract directives. A Postprocessor (priority 25) injects labels, classes, and prefix markup into rendered HTML.

  2. Embeds use Preprocessors (priority 20) that run after superfences, matching standalone [name ...] lines. Social embeds add a Postprocessor (priority 15) for one-time script injection.

  3. Highlight uses an InlineProcessor (priority 175) for regular text, plus a Postprocessor (priority 25) for <^> markers inside code blocks where the delimiters are HTML-escaped.

License

This project is a port of do-markdownit by DigitalOcean, which is licensed under the Apache License 2.0. See the NOTICE file for attribution details.