Fast, portable, fully offline Markdown viewer/editor for Windows.
Project description
What it is
A small Windows desktop app that opens a .md file and renders it beautifully — with KaTeX math, Mermaid diagrams, syntax-highlighted code, live reload when the file changes on disk, and a three-mode Read / Edit / Source view. Everything needed to render is vendored into the package: no network request is made to open or view a document.
Why
Most Markdown viewers either need a browser tab, a heavy IDE, or pull fonts and scripts from a CDN at render time. mdvw is a single pip install away, opens fast, and works without internet — everything needed to render ships inside the wheel.
Features
- Three modes — Read, Edit (live split), Source (raw
.mdin a dark editor). Switch withCtrl+1/2/3or cycle withE. - Offline first — KaTeX (math), Mermaid (diagrams), highlight.js (20 languages), and webfonts all ship inside the wheel, SHA256-pinned via a manifest.
- GFM + extensions — tables, task lists, footnotes, strikethrough. Plus
==highlight==,++underline++, and{color:red}…{/color}/{color:#hex}…{/color}. - Wiki links —
[[Note]],[[Note|alias]],[[Note#Heading]],[[#Heading]]. Click to navigate, type[[for filename autocomplete, click an unresolved link to create the note. Backlinks live in the Incoming sidebar pane; Diagnostics flags ambiguous and missing-heading targets. - YAML frontmatter card —
----fenced metadata renders as a styled card at the top of the preview; invalid YAML shows an error card without breaking the body. - Live reload — external changes on disk re-render instantly; unsaved edits get a conflict prompt rather than being silently overwritten.
- Command palette —
Ctrl+Pblends slash-commands with filename matches from the workspace into one fuzzy-searchable input. - Find in document + workspace search —
Ctrl+Ffor an in-page find bar (match count, case/whole-word toggles);Ctrl+Shift+Fgreps every.mdunder the launch directory and jumps to the match. - Outline, files, recent, diagnostics — switchable left-pane sections. The outline supports per-heading collapse plus
▲ All/▼ All/▶ Auto. Diagnostics flag invalid frontmatter, broken relative links, and blocked remote refs. - Inspector + status bar — right-pane inspector shows parsed frontmatter and document stats (words, headings, reading time); footer status bar tracks mode, dirty state, word count, cursor position, and the mdvw version.
- Image paste — pasting an image in the editor saves it next to the document and inserts a relative
reference. - Export + print —
Export HTML…writes a single self-contained file (inlined CSS, fonts, and image data URIs);Print…hands off to the system print dialog for print-to-PDF. - Native feel — system tray with close-to-tray, single-instance file handoff, follow-system dark/light theme (title bar included), taskbar icon (M↓),
.mdfile association viamdvw --register.
Install
pip install mdvw
Requires Python 3.13+, Windows 10/11.
Or grab the standalone onedir build from the Releases page — unzip mdvw-win-x64.zip and run mdvw.exe. No Python needed.
Usage
mdvw notes.md # open a file
mdvw # open with the bundled welcome doc
mdvw --edit notes.md # start in split-edit mode
mdvw --no-tray # skip the system tray icon
mdvw --register # associate .md with mdvw (HKCU, no admin)
mdvw --unregister # remove the association
Keyboard shortcuts
| Key | Action |
|---|---|
Ctrl+P |
Command palette (commands + workspace filenames) |
Ctrl+1 / Ctrl+2 / Ctrl+3 |
Read / Edit (split) / Source |
E |
Cycle Read → Edit → Source |
Ctrl+O |
Open file |
Ctrl+S |
Save (atomic; prompts on disk conflict) |
Ctrl+F |
Find in document |
Ctrl+Shift+F |
Search workspace |
Ctrl+Shift+H |
Go to heading |
Ctrl+Shift+O |
Open directory |
Alt+Left / Alt+Right |
Back / Forward through visited documents |
[[ |
Wiki-link filename autocomplete (in Edit / Source) |
Ctrl+Shift+W |
Toggle narrow / wide preview |
Ctrl+Alt+I |
Toggle inspector |
Markdown extensions
Beyond GitHub Flavored Markdown, mdvw understands:
==highlighted== text
++underlined++ text
{color:orange}orange{/color}, {color:#bf3989}pink{/color}
[[Note]], [[Note|alias text]], [[Note#Heading]], [[#Same-doc heading]]
Inline math $e^{i\pi}+1=0$ and block math:
$$
x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
$$
Mermaid diagrams:
```mermaid
graph LR
A[Open .md] --> B[Edit]
B --> C[Preview]
C --> D[Save]
```
Safety notes
Documents render through an HTML sanitizer with no network access, so opening an unfamiliar .md file doesn't fetch remote resources or leak that you opened it. Saves are atomic and notice when the file changed on disk between load and save. Vendored JS/CSS is SHA256-pinned and verified in CI.
How it works (one paragraph)
render.py parses Markdown with markdown-it-py + plugins, sanitizes with nh3 (Rust ammonia), and rewrites user-relative URLs against the document's own directory. app.py renders a template into a per-instance HTML in %TEMP%, references packaged JS/CSS via absolute file:// URLs (no <base> — that would misdirect user links), and opens it in a pywebview window using Windows WebView2. KaTeX / Mermaid / highlight.js run in the browser post-inject.
Releasing
The project uses a single-commit + tag pattern so the PyPI artifact's source matches the tag byte-for-byte:
# 1. Write notes under `## [Unreleased]` in CHANGELOG.md, commit
# 2. Cut the release (atomic bump + changelog date + commit + tag):
python scripts/release.py 0.2.0
git push origin main v0.2.0 # triggers release.yml → PyPI + GH Release
# 3. Open the next dev cycle:
python scripts/release.py --post-release 0.3.0.dev0
git push origin main
Development
git clone https://github.com/ThomasRohde/mdvw && cd mdvw
pip install -e .[dev]
python scripts/fetch_vendor.py --verify # make sure vendor hashes match
pytest -q # run tests
ruff check src tests scripts # lint
python -m mdvw README.md # try it
To upgrade a vendored library: python scripts/fetch_vendor.py --update, then commit the refreshed files and manifest.json together.
License
MIT. The bundled third-party assets keep their own licenses (KaTeX: MIT; Mermaid: MIT; highlight.js: BSD-3).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mdvw-0.9.0.tar.gz.
File metadata
- Download URL: mdvw-0.9.0.tar.gz
- Upload date:
- Size: 1.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
229c5f4332aa1ea6fd72ac197a8f710690f7660856dfd9f93502998d88ce959e
|
|
| MD5 |
adcecb5ea067a41b2352f9db3cd6a6b8
|
|
| BLAKE2b-256 |
ce1748dd8e5e001c994660795b08a72cb13195721cb343e94f35968b2c671870
|
Provenance
The following attestation bundles were made for mdvw-0.9.0.tar.gz:
Publisher:
release.yml on ThomasRohde/mdvw
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mdvw-0.9.0.tar.gz -
Subject digest:
229c5f4332aa1ea6fd72ac197a8f710690f7660856dfd9f93502998d88ce959e - Sigstore transparency entry: 1338774718
- Sigstore integration time:
-
Permalink:
ThomasRohde/mdvw@e339ccfa1b1981f63db1360f53f978515dda2102 -
Branch / Tag:
refs/tags/v0.9.0 - Owner: https://github.com/ThomasRohde
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e339ccfa1b1981f63db1360f53f978515dda2102 -
Trigger Event:
push
-
Statement type:
File details
Details for the file mdvw-0.9.0-py3-none-any.whl.
File metadata
- Download URL: mdvw-0.9.0-py3-none-any.whl
- Upload date:
- Size: 1.3 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e7c488872eb74198fdc6fd6d706d3d52ccc3ec50bc6521544455d77e49e38962
|
|
| MD5 |
12e8acd7eb2742965fbd74ba34b4751a
|
|
| BLAKE2b-256 |
b83e4f75f6240830f361bfb0ddf7c2600ef6b71ff72905c099039829f343ef05
|
Provenance
The following attestation bundles were made for mdvw-0.9.0-py3-none-any.whl:
Publisher:
release.yml on ThomasRohde/mdvw
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mdvw-0.9.0-py3-none-any.whl -
Subject digest:
e7c488872eb74198fdc6fd6d706d3d52ccc3ec50bc6521544455d77e49e38962 - Sigstore transparency entry: 1338774720
- Sigstore integration time:
-
Permalink:
ThomasRohde/mdvw@e339ccfa1b1981f63db1360f53f978515dda2102 -
Branch / Tag:
refs/tags/v0.9.0 - Owner: https://github.com/ThomasRohde
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e339ccfa1b1981f63db1360f53f978515dda2102 -
Trigger Event:
push
-
Statement type: