Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Conversion Modes

A conversion mode selects a preset of ConversionOptions fields. mdka reads these fields directly during its single-pass DOM traversal — there is no separate pre-processing stage.

Overview

ModeDefault?Converts
Balanced✅ YesGeneral use
MinimalDifferently: drops shell elements, emits no id anchors

There are two modes, and they make two behaviours.

Removed in 3.0: Strict, Semantic and Preserve

Until 3.0 there were five modes. Strict, Semantic and Preserve were aliases of Balanced: they produced byte-for-byte the same output and could not differ, so they were deprecated in 2.8.0 and removed in 3.0.

Why they could not differ: the presets differed from each other only in the defaults of six fields that could not change the output — five about HTML attributes, for which Markdown has no syntax, and one about wrapper elements, whose unwrapping leaves no trace in Markdown. Their names described purposes (“for debugging”, “for archiving”, “for accessibility”) that the conversion could not act on. Nothing that used one converts differently now; the name only has to change.

What to do: use Balanced, or name no mode at all. Use Minimal if you wanted something genuinely different.

What you see if you still name one, on each surface — all of them fail, and say removed rather than unknown, because a removed name is an obsolete configuration, not a wrong one:

SurfaceWhat happens
Rust, "strict".parse::<ConversionMode>()Err("conversion mode 'strict' was removed in 3.0; it was an alias of 'balanced'. Use 'balanced'."). The variants ConversionMode::Strict, Semantic and Preserve no longer exist, so naming one is a compile error. ConversionMode::parse_mode returns None and no message, as it does for any name it does not accept — which is why it is deprecated since 3.0.0 in favour of str::parse, which reports why a name was rejected
Node.jshtmlToMarkdown and htmlToMarkdownMany throw, and htmlToMarkdownAsync and the file functions reject, with the same message
PythonConversionMode.Strict, Semantic and Preserve do not exist: AttributeError. A mode is never a string in Python, so there is no string form
CLImdka --mode strict exits with status 1 and prints error: conversion mode 'strict' was removed in 3.0; it was an alias of 'balanced'. Use 'balanced'. on stderr

A name that never existed (--mode bogus) still gets the unknown message, with the list of valid modes.

It is asserted, not just observed. tests/output_validity/mode_identity.rs runs a corpus of inputs — including wrappers in table cells, list items, quotes and <pre> — through Balanced and Minimal and fails if either differs by a byte from what the published 2.9.0 produced (P3).

Minimal is the only mode that converts differently from Balanced — it drops shell elements (drop_interactive_shell) and does not emit id anchors (preserve_ids).


Balanced (default)

What it does: keeps id attributes (emits anchors) and keeps shell elements (nav/header/footer/aside). A wrapper element (<div>, <section>, <article>, <main>) is rendered as the paragraph break it stands for.

let md = mdka::html_to_markdown(html); // Balanced is the default

Use when: you want the default behaviour without extra configuration.


Minimal

What it does: drops shell elements (nav/header/footer/aside and their children), does not emit id anchors, and unwraps wrapper elements — which changes nothing in the output on its own, since unwrapping keeps the paragraph break the wrapper stood for.

One thing it does change: with emphasis_from_style on, a wrapper’s own inline style is what would have carried the bold/italic — unwrapping discards the tag, and there is nothing left to read it from. A <span style="font-weight:700"> that would gain bold in Balanced gains nothing in Minimal, including the Google Docs paste shape the option exists for (see that page for the example). This is not a limit of the option; it follows from Minimal unwrapping the element before anything downstream can read it.

The most aggressive mode for extracting body content — useful for piping into an LLM prompt or a search index, where surrounding navigation chrome is noise.

let opts = ConversionOptions::for_mode(ConversionMode::Minimal);
let md = mdka::html_to_markdown_with(html, &opts);

Choosing a Mode

Want the most aggressive extraction (LLM input, etc.)? → Minimal
Everything else                                        → Balanced (default)