Skip to content

Repository files navigation

mdformat-mkdocs

Build Status PyPI version

An mdformat plugin for mkdocs and packages commonly used with MkDocs (mkdocs-material, mkdocstrings, and python-markdown)

mdformat-mkdocs also intentionally supports Zensical, which is working toward feature parity with mkdocs (as of mid-2026) and may ship features ahead of it.

Supports:

  • Indents are converted to four-spaces instead of two
    • Note: when specifying --align-semantic-breaks-in-lists, the nested indent for ordered lists is three, but is otherwise a multiple of four
  • Unordered list bullets are converted to dashes (-) instead of *
  • By default, mdformat-mkdocs standardizes ordered lists on a single digit (1. or 0.); with --number, it applies consecutive numbering instead, for consistency with mdformat
  • MkDocs-Material Admonitions*
    • *Note: mdformat-admon formats the same admonitions; this package adds an extra space for consistency with the mkdocs styleguide (#22)
  • MkDocs-Material Content Tabs*
    • *Note: this plugin renders markup (HTML) good enough for formatting but not for viewing in a browser. Open an issue if you need valid HTML.
  • MkDocs-Material Definition Lists
  • mkdocstrings Injection Blocks
    • Preserves ::: identifier blocks and their indented YAML options verbatim, including when nested inside lists with --align-semantic-breaks-in-lists
  • mkdocstrings Anchors (autorefs)
  • mkdocstrings Cross-References
  • Python Markdown "Abbreviations"*
    • *Note: the abbreviation markup (HTML) isn't useful for rendering. If you need it, I'm open to contributions; the implementation isn't simple
  • Python Markdown "Attribute Lists"
    • Preserves attribute list syntax when using --wrap mode
  • PyMdown Extensions "Arithmatex" (Math/LaTeX Support) (Material for MkDocs Math)
    • This plugin combines three math rendering plugins from mdit-py-plugins:
      1. dollarmath: Handles $...$ (inline) and $$...$$ (block) with smart dollar mode that prevents false positives (e.g., $3.00 is not treated as math)
      2. texmath: Handles \(...\) (inline) and \[...\] (block) LaTeX bracket notation
      3. amsmath: Handles LaTeX environments like \begin{align}...\end{align}, \begin{cases}...\end{cases}, \begin{matrix}...\end{matrix}, etc.
    • Can be deactivated entirely with the --no-mkdocs-math flag
  • Python Markdown "Snippets"*
    • *Note: the markup (HTML) renders the plain text without implementing the snippet logic. I'm open to contributions if anyone needs full support for snippets
  • PyMdown "Blocks"* (/// name fenced syntax, e.g. admonition, details, tab, html, definition, expand, markdown, or any third-party block type): options directly after the header keep their original indentation, and nested content is formatted like any other markdown (#88)
    • *Note: /// caption, /// figure-caption, and /// table-caption blocks are normalized separately, see PyMdown "Blocks: Caption" below
    • *Note: a literal /// line inside a fenced code block that's part of a block's content is misread as the block's closing fence; wrap such content so no line is a bare ///, or open an issue if this affects you
  • PyMdown "Blocks: Caption": /// caption, /// figure-caption, and /// table-caption are normalized to /// {type} | {number} with the attrs option indented four spaces

Features with Implicit Support

The following MkDocs/Material/PyMdown syntax passes through mdformat-mkdocs unchanged, preserved as written but not actively normalized:

Note on PyMdown ProgressBar: the syntax [=50% "50%"] looks like an undefined link reference, so mdformat-mkdocs escapes it to \[=50% "50%"\] by default. Use --ignore-missing-references to keep it as-is, or skip this extension if you run mdformat without that flag.

See the example test files, ./tests/pre-commit-test.md and ./tests/format/fixtures.md

mdformat Usage

Add this package wherever you use mdformat; it auto-recognizes the plugin, no configuration needed. For more on plugins, see the official mdformat documentation

Required Extras

Always installed to prevent corruption to footnotes and frontmatter syntaxes supported by MkDocs out of the box:

The mkdocs extension chains all three automatically, so mdformat.text(src, extensions={"mkdocs"}) formats tables, frontmatter, and footnotes without naming each plugin.

This only affects the Python API. mdformat's CLI auto-activates every installed plugin, so it never needed this fix. The API activates only the extensions you name, even when a plugin's package is installed. Before this chaining was added, extensions={"mkdocs"} alone left tables squished and footnote references escaped (#87).

Optional Extras

This package also specifies two "extra" plugins ('recommended' and 'recommended-mdsf') for plugins that work well with typical documentation managed by mkdocs:

pre-commit/prek

repos:
  - repo: https://github.com/executablebooks/mdformat
    rev: 1.0.0
    hooks:
      - id: mdformat
        additional_dependencies:
          - mdformat-mkdocs
          # Or
          # - "mdformat-mkdocs[recommended-mdsf]>=5.3.0"
          # Or
          # - "mdformat-mkdocs[recommended]>=5.3.0"

uvx

uvx --with=mdformat-mkdocs mdformat

Or with pipx:

pipx install mdformat
pipx inject mdformat mdformat-mkdocs

HTML Rendering

To generate HTML output, import any of the plugins from mdit_plugins. For more on MarkdownIt, see the docs: https://markdown-it-py.readthedocs.io/en/latest/using.html#the-parser

from markdown_it import MarkdownIt

from mdformat_mkdocs.mdit_plugins import (
    material_admon_plugin,
    material_content_tabs_plugin,
    mkdocstrings_autorefs_plugin,
    mkdocstrings_crossreference_plugin,
    pymd_abbreviations_plugin,
)

md = MarkdownIt()
md.use(material_admon_plugin)
md.use(material_content_tabs_plugin)
md.use(mkdocstrings_autorefs_plugin)
md.use(mkdocstrings_crossreference_plugin)
md.use(pymd_abbreviations_plugin)

text = "- Line 1\n    - `bash command`\n    - Line 3"
md.render(text)
# <ul>
# <li>Line 1
# <ul>
# <li><code>bash command</code></li>
# <li>Line 3</li>
# </ul>
# </li>
# </ul>

Configuration

mdformat-mkdocs adds the CLI arguments:

  • --align-semantic-breaks-in-lists optionally aligns semantic line breaks (continuation lines that aren't a nested list, code block, or admonition) to the width of the list marker: 3 spaces for numbered lists, 2 spaces for bulleted lists. Without it, mdformat-mkdocs applies the 4-space indent everywhere.

    # with: mdformat
    1. Semantic line feed where the following line is
        three spaces deep
    
    - Semantic line feed where the following line is
        two spaces deep
    
    # vs. "mdformat --align-semantic-breaks-in-lists"
    1. Semantic line feed where the following line is
       three spaces deep
    
    - Semantic line feed where the following line is
      two spaces deep
  • --ignore-missing-references, if set, stops mdformat-mkdocs from escaping link references that have no definition. Required when references are dynamic, such as with python mkdocstrings

  • --no-mkdocs-math, if set, turns off math/LaTeX rendering (Arithmatex), which is on by default. Useful for formatting markdown without processing math syntax.

You can also use the toml configuration (https://mdformat.readthedocs.io/en/stable/users/configuration_file.html):

# .mdformat.toml

[plugin.mkdocs]
align_semantic_breaks_in_lists = true
ignore_missing_references = true
no_mkdocs_math = true

Contributing

See CONTRIBUTING.md

About

An mdformat plugin for mkdocs and Material for MkDocs

Topics

Resources

Contributing

Stars

31 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages