mdui-tui
v0.1.1
Published
Terminal Markdown renderer and viewer — open, navigate, search, copy, and export Markdown files from the CLI with vim keybindings and interactive finder.
Maintainers
Readme
MDUI
MDUI is a Bun-powered terminal Markdown renderer built with strict TypeScript and OpenTUI. It opens a fast Markdown finder for a directory, renders local or remote Markdown documents in a read-only TUI, and adds vim-style navigation, search highlighting, visual selection, Slack/PDF export, line numbers, internal Markdown links, and compact in-app overlays.
OpenTUI currently targets Bun, so MDUI runs on Bun rather than Node.
Features
- Interactive Markdown finder rooted at the current directory.
- Remote
.mdURL rendering, including in-app navigation for remote Markdown links. - Rich OpenTUI Markdown rendering with full-width grid tables and OSC-8 terminal hyperlinks.
- Read-only vim-style navigation with counts (
8j,4k,42G),gg/G, visual and visual-block selection. - Document search with cached matches, visible match highlights, and
n/Nrepeat navigation. - Table-of-contents overlay plus footer word count and reading-time estimates.
- Internal Markdown navigation for relative
.mdlinks and[[wikilinks]], with session back/forward history. - Visual-only line numbers that are excluded from copied content.
- Clipboard helpers: copy selection/document through OSC52 with native clipboard fallbacks, copy Slack mrkdwn, and export PDF to
~/Downloads. mdui helpandCtrl-//Ctrl-?/Ctrl-Shift-?in-app help.
Install
npm (recommended)
# Global install
npm install -g mdui-tui
# Or add to a project
npm install mdui-tuiAfter a global install, mdui is on your PATH. Just run:
mdui README.md
mdui https://telnyx.com/pricing.md
mdui # interactive finder
mdui helpRequires Bun. MDUI uses OpenTUI which targets the Bun runtime. Make sure
bunis installed first.
From source
git clone https://github.com/Aaronjo03/mdui-tui.git
cd mdui-tui
bun install
bun run buildRun from the checkout:
bun run src/cli.ts README.md
bun run src/cli.ts
bun run src/cli.ts helpOr link the built CLI locally:
ln -sf "$PWD/dist/cli.js" ~/.local/bin/mdui
ln -sf "$PWD/dist/cli.js" ~/.local/bin/MDUIUsage
mdui <file.md>renders a Markdown file directly.mdui <https://example.com/file.md>fetches and renders a remote Markdown file directly.mduiopens an interactive Markdown finder rooted at the current directory.mdui helpprints CLI and in-app keybinding help.
After bun run build, the compiled binary entry is dist/cli.js. Chrome/Chromium/Edge is required for PDF export.
Keybindings
Finder
| Key | Action |
| --- | --- |
| j/k or ↓/↑ | Move file selection |
| / | Filter Markdown files |
| Backspace | Remove filter character |
| Enter | Open selected Markdown file |
| q or Ctrl-C | Quit |
Document view
| Key | Action |
| --- | --- |
| arrows or h/j/k/l | Move the read-only cursor |
| 8j, 4k, 5l | Prefix motions with a Vim-style count |
| 0 | Move to the start of the current line |
| Ctrl-d | Scroll half a page down |
| Ctrl-f / Ctrl-b | Scroll a page |
| gg / G / 42G | Jump to top / bottom / line 42 |
| Tab | Toggle the file sidebar |
| Esc | Clear search, exit visual mode, or reopen the sidebar |
| / | Search document when fullscreen; filter files when the sidebar is visible |
| Enter while searching | Confirm the current document search |
| n | Move to the next search match |
| N or p | Move to the previous search match |
| t | Toggle the table-of-contents overlay |
| v / Ctrl-v | Start visual / visual-block selection |
| y | Yank visual / visual-block selection and clear the highlight |
| c | Copy highlighted text, or the whole document when nothing is highlighted |
| o or Enter | Open the first link on the current line; relative Markdown links, remote .md URLs, and [[wikilinks]] open inside MDUI |
| mouse click on a link line | Open the clicked-line link with the same internal/external routing |
| Ctrl-o / Ctrl-i | Navigate back / forward through internal Markdown links |
| Ctrl-y | Copy the current document as Slack mrkdwn |
| Ctrl-p | Export the current document to ~/Downloads/<filename>.pdf |
| Ctrl-u | Paste/type a remote Markdown URL to open inside MDUI |
| Ctrl-/, Ctrl-?, or Ctrl-Shift-? | Toggle the in-app help panel |
| Ctrl-+ / Ctrl-- | Increase or decrease document wrapping width |
| w | Toggle line wrapping on or off |
MDUI remembers the cursor line and scroll position per file for the current session only, watches local files for changes, and reloads them in place. Remote Markdown documents are fetched into temporary local files for the session. Line numbers are visual-only and are not part of copied Markdown content.
Configuration
Interactive mode loads JSON configuration from the first matching source:
MDUI_CONFIG=/path/to/config.json.mduirc,.mdui.json, ormdui.config.jsonin the current directory or a parent directory$XDG_CONFIG_HOME/mdui/config.json(or~/.config/mdui/config.json)
Supported options are data-only settings:
{
"includeHidden": false,
"maxDepth": 8,
"ignoredDirectories": ["vendor", "tmp-notes"],
"pdfOutputDirectory": "/Users/me/Downloads"
}Config files cannot define shell commands or keybindings. Clipboard fallbacks are fixed platform commands (pbcopy, wl-copy, xclip, xsel, or clip.exe) and receive copied text on stdin.
Development
bun install
bun "node_modules/typescript/bin/tsc" --noEmit -p tsconfig.test.json
bun run test
bun "node_modules/typescript/bin/tsc" -p tsconfig.jsonnpm publishing prep
The package is named mdui-tui and exposes mdui / MDUI binaries from dist/cli.js. dist/ is intentionally ignored in git; the prepack script builds it before packaging.
Install and run in one shot:
npm install -g mdui-tui # requires bun on PATH
mdui README.md # render a file to stdout (no TTY needed)
mdui # interactive finder (requires TTY)Non-interactive / pipe-friendly: mdui <file.md> renders ANSI-formatted Markdown to stdout. No TTY required — works in scripts, pipes, and CI. The interactive finder (bare mdui) requires a TTY and exits with code 1 if stdin/stdout is not a terminal.
Exit codes:
| Code | Meaning | |------|----------| | 0 | Success | | 1 | Error (non-TTY for interactive mode, file not found, invalid config, PDF export failure) |
Config discovery order (first match wins):
MDUI_CONFIGenv var → absolute path to a JSON config file- Walk up from cwd:
.mduirc,.mdui.json, ormdui.config.json $XDG_CONFIG_HOME/mdui/config.json(default~/.config/mdui/config.json)
Full config schema:
{
"includeHidden": false,
"maxDepth": 8,
"ignoredDirectories": ["vendor", "node_modules", "tmp-notes"],
"pdfOutputDirectory": "/Users/me/Downloads"
}maxDepth: integer 0–32, default 8. Directory traversal depth for the finder.ignoredDirectories: directory names only (no/or\). Matched by basename, not path.pdfOutputDirectory: must be < 4096 chars, no null bytes. Default~/Downloads.- Config is data-only. No shell commands, no keybindings, no arbitrary code execution.
PDF export requires Chrome, Chromium, or Edge on PATH. Uses --headless=new mode. Output goes to pdfOutputDirectory (default ~/Downloads/<filename>.pdf).
Internal link resolution: Relative Markdown paths and [[wikilinks]] resolve against the file's directory. Remote .md URLs open inside MDUI; other external links (http://, https://) open in the default browser. Navigate back/forward with Ctrl-o/Ctrl-i.
Clipboard chain: OSC 52 → pbcopy (macOS) / wl-copy (Wayland) / xclip or xsel (X11) / clip.exe (Windows). All receive text on stdin — no shell injection surface.
Integration example — render a changelog in CI:
npm install -g mdui-tui
mdui CHANGELOG.md > changelog-ansi.txt # ANSI-formatted, pipe-safeStar the repo for updates:
gh repo star Aaronjo03/mdui-tuiLicense
MIT © Aaron Johnson
Samples
samples/feature-tour.mdexercises headings, tables, lists, links, blockquotes, and command-output code fences.samples/commands.mdfocuses on terminal-command notes and process-table rendering.
