htmd
A fast, turndown.js-inspired HTML to Markdown converter for Rust with rich options and table support.
Repository Health
Technical Analysis
htmd is a Rust library that converts HTML into clean Markdown, closely modeled on the popular turndown.js JavaScript converter. It passes all of turndown.js’s test cases, supports HTML-to-Markdown table conversion, and keeps its dependency footprint minimal by relying only on html5ever for parsing.
Designed for speed and correctness, htmd converts a 1.37MB Wikipedia page in roughly 16ms and exposes a builder-based API for skipping tags, customizing output options, and registering per-tag handlers. A faithful mode can preserve raw HTML for elements Markdown cannot represent, making it a solid choice for content pipelines, scrapers, and LLM ingestion.
What You Get
- A one-line htmd::convert function plus a builder-based HtmlToMarkdown API for advanced configuration
- Full turndown.js-compatible conversion that passes all of turndown.js’s test cases
- HTML table to Markdown table conversion out of the box
- Configurable Options covering heading style, list markers, code-block fences, link styles, and more
- Custom per-tag handlers and tag-skipping for fine-grained control over output
- A faithful mode that preserves raw HTML for tags Markdown cannot express
Common Use Cases
- Converting scraped or fetched web pages into Markdown for storage or display
- Preparing clean Markdown text from HTML for LLM ingestion and RAG pipelines
- Building content-migration tools that move HTML documents into Markdown-based systems
- Normalizing rich HTML email or CMS content into portable Markdown
Under The Hood
Architecture - The entry point src/lib.rs parses HTML into an html5ever RcDom via html_to_tree, then walks the tree with dom_walker::walk_node, dispatching each element to a registered ElementHandler. Handlers live in src/element_handler (one module per tag family: headings, list, li, table, td_th, anchor, code, pre, blockquote, and more), each returning a HandlerResult that the walker concatenates and post-trims. A builder assembles ElementHandlers keyed by tag, so custom handlers and tag-skipping simply insert into that map.
Tech Stack - Written in Rust (edition 2024), htmd depends only on html5ever and markup5ever_rcdom for parsing plus phf for compile-time perfect-hash tag lookup. Dev tooling uses criterion for benchmarks and indoc, scraper, and pretty_assertions for tests. Options are modeled as plain enums in src/options.rs (HeadingStyle, HrStyle, CodeBlockFence, BulletListMarker, TranslationMode, etc.) with sensible defaults.
Code Quality - The codebase is well factored, with a clear DOM-walk plus per-tag-handler separation and doc-commented public types. Testing is thorough: roughly 86 test functions across tests/ (basic, link, list, table, and turndown-compatibility suites) plus inline unit tests, and the README documents passing all turndown.js cases. Naming is consistent and error handling surfaces through std::io::Result.
API Design - The public surface is deliberately small and ergonomic: htmd::convert for a one-liner and HtmlToMarkdown::builder() for a fluent, chainable configuration flow (options, skip_tags, add_handler, scripting_enabled). Custom handlers are ordinary closures receiving an Element, and the converter is Send/Sync-friendly for multithreaded use, keeping boilerplate minimal to get started.
Used by 2 apps in this directory
fabro
Developer Tools · Devops
Define AI agent workflows as code graphs, route tasks across any LLM, and intervene only where it matters.
Tabby
AI Code Assistants
Self-hosted AI coding assistant — run GitHub Copilot-grade code completion on your own hardware with no cloud dependency.