Online Markdown Preview: Real-time Render and Edit Markdown
What Is Markdown
Markdown is a lightweight markup language proposed by John Gruber in 2004. Readable plain text expresses headings, lists, links, and more; a parser turns that into HTML or other formats. It is the default writing surface for technical docs, READMEs, blogs, and notes.
To move the same content between HTML and Markdown, use the HTML ↔ Markdown converter. To see final layout while writing, use Markdown Preview.
Why Preview Matters
“Looks aligned in the source” is not the same as “renders aligned.” Preview mainly catches three classes of failure:
- Structure: table separator column count mismatches, unclosed fences, nested-list indent off by one
- Dialect: GFM tables published into a CommonMark-only renderer become literal pipes
- Pre-publish checks: task lists, quotes, and links still behave on the destination site
Prose paragraphs rarely need constant preview; tables, nested lists, and fenced code blocks are the high-ROI cases.
How to Use ToolVault Markdown Preview
Open Markdown Preview:
- Default view is split: source on the left (Monaco / CodeEditor), live render on the right
- Switch to source or preview only; the preference is stored under the local key
tool:markdown:view - First load includes a GFM sample (headings, task list, table, quote, fenced code)—edit it to verify behavior
- Use Copy HTML in the toolbar for a marked-rendered HTML string (same GFM dialect as the converter). You can still take the Markdown source, or edit both directions in the converter
Rendering stays in the browser; the body is not POSTed for preview.
CommonMark vs GFM: Fidelity Starts Here
Markdown fragmented as soon as it succeeded:
| Dialect | Role | This preview |
|---|---|---|
| Original Markdown | Gruber’s description + ambiguous implementations | Not a separate target |
| CommonMark | Shared base for modern parsers | Portable core syntax |
| GFM | CommonMark superset: tables, strikethrough, task lists, autolinks, footnotes, … | Target dialect (remark-gfm) |
| Site-specific extensions | Frontmatter, math, admonitions, shortcodes | Not guaranteed; preview on the destination |
GFM tables on a pure CommonMark renderer show up as pipe characters. Task lists on an old wiki that ignores them degrade to ordinary list text.
MediaWiki, some legacy CMSes, and chat Markdown subsets need a second preview on that system. This tool matches developer-docs GFM, not the union of every dialect.
Syntax Supported Here
Headings, emphasis, lists, links
# Heading 1
## Heading 2
**Bold** and *italic*; inline code uses backticks.
- Unordered item
1. Ordered item
[Link text](https://example.com)

> Blockquotes can span lines
Strikethrough (~~text~~) is GFM, not strict CommonMark core.
Fenced code blocks
Put a language tag after the opening fence (for example the tag js). This tool wraps content in monospace pre / code and may expose a language-* class—there is no syntax-highlighter plugin, so you will not see colored keywords. Highlighting needs rehype-highlight / Prism (or the destination docs site).
Tables (GFM)
| Env | Host | Traffic |
|---|---|---:|
| prod | www.example.com | 100% |
| staging | staging.example.com | internal |
Rules of thumb:
- The
|---|separator row must match the header column count, or the table often collapses to plain text - Alignment uses colons in the separator:
:---left,---:right,:---:center - Escape
|inside cells as\| - Space-padding is for humans reading source; renderers do not require aligned spaces
Build tables visually with the Markdown table generator, then paste back here to confirm.
Task lists (GFM)
- [x] Done
- [ ] Todo
Preview shows disabled checkboxes for display. Interactive toggling that writes back into the source is out of scope.
Autolinks
Bare URLs such as https://example.com often become clickable under GFM. Email-literal behavior varies slightly by parser—trust the preview.
Common extensions this tool does not implement
| Construct | Here |
|---|---|
:smile: emoji shortcodes | Not expanded; paste Unicode emoji instead |
$E=mc^2$ / KaTeX | No math rendering |
| Admonition / callout shortcodes | Unrecognized (unless written as normal quotes/HTML elsewhere) |
| YAML frontmatter | Shown as body text; metadata is not stripped |
Safe Rendering and XSS Boundaries
The pipeline is:
source string → remark (+ remark-gfm) → react-markdown React elements → Tailwind Typography (prose) styles
Boundaries aligned with the current dependencies (other sites may differ):
-
Raw HTML in the Markdown source is not treated as an executable DOM fragment
react-markdowntends to escape or skip HTML rather than inject viadangerouslySetInnerHTML. Older copy that claims “script tags run in preview” is wrong for this tool. “You can mix HTML” in many platforms describes their dialect—not a guarantee here. -
Link and image URLs pass through the default
urlTransform
Dangerous schemes such asjavascript:are blocked. Do not disable or replace that transform with a pass-through—that is an XSS hole. -
No separate
rehype-sanitizeallowlist plugin
Safety comes mainly from the Markdown→React model plus URL transforms, not a second HTML sanitizer. If you paste HTML from the converter into your page withinnerHTML, that is a different threat model—use your own sanitizer, or see the HTML entity encoder guide. -
Images and external links still have side effects
triggers a browser request. Local preview does not mean “image URLs are free of privacy or mixed-content issues.” -
Contrast: converter Markdown → HTML
The HTML ↔ Markdown tool usesmarked.parseto emit an HTML string into an editor (as text), not this React path. Whether that string is safe depends on how you embed it later.
Preview vs publish: two different jobs
Local preview answers “does this GFM document parse the way I think?” Publishing answers a longer checklist: frontmatter metadata, image CDN paths, absolute vs relative links, MDX/JSX rules (a bare less-than sign in prose can break MDX), and site-specific shortcodes. Treat this tool as a syntax and layout smoke test, not a substitute for the destination build.
A practical loop that saves review cycles:
- Draft structure here (headings, tables, task lists) until the split view looks right
- Paste fenced configs through YAML ↔ JSON or the JSON formatter so examples are valid before they enter the README
- Run the destination preview (GitHub PR, docs site, CMS) once for dialect extras this page does not claim
If step 3 fails while step 1 looked fine, the bug is almost always an extension or sanitizer—not headings or bold. Keep a two-line repro of the failing construct (one table row, one nested list) so reviewers are not comparing whole READMEs. When the destination adds plugins (math, admonitions, mermaid), list those explicitly in the PR so nobody treats this browser preview as the final renderer.
Copy HTML vs on-screen preview
Toolbar Copy HTML runs marked (GFM) and puts an HTML string on the clipboard. The right-hand pane still uses react-markdown + remark-gfm. Both target GFM tables and task lists, but they are not the same code path:
| Path | Output | Safe to paste into a live page? |
|---|---|---|
| On-screen preview | React elements under Typography | Yes — stays inside React |
| Copy HTML | HTML string from marked | Only after your sanitizer / CSP policy |
Use Copy HTML for email templates, static snippets, or CMS fields that expect markup. Do not treat the clipboard string as “already sanitized for production.”
Frequent Pitfalls
Unclosed fences
A missing closing fence turns the rest of the document into code—the tell is “everything after line N is monospace.”
Nested list indentation
Sub-items usually align with the parent text (commonly 2 or 4 spaces). Mixing tabs and spaces is inconsistent across engines; this page follows CommonMark/GFM—trust the preview.
Hard breaks vs paragraphs
With break-joining semantics, a single newline often stays inside one paragraph. Hard breaks need trailing spaces or a blank line. GitHub comments and some chat clients are more aggressive—do not assume “newline in source = newline in preview.”
Footnotes and reference-style links
GFM footnotes ([^1]) render when the destination supports them; this preview follows remark-gfm footnote rules. Reference-style links ([text][id] with a definition later) are easy to break if the definition line is indented into a list or fenced block—keep definitions at column zero.
When preview and production disagree
- Minimize to a two-line repro
- Confirm both sides are GFM (especially tables / task lists / strikethrough)
- Check whether the destination strips HTML, changes autolinks, or adds math plugins
The culprit is almost always an extension boundary, not core # / ** syntax.
Working with YAML, JSON, Diff, and HTML
| Scenario | Path |
|---|---|
| Config snippets in a README | Normalize with YAML ↔ JSON, then fence; read the YAML JSON guide |
| API examples in docs | JSON formatter before the code block; see the JSON formatting guide |
| Two versions of a doc/config | Text Diff; see the text Diff guide |
| Web page → Markdown | HTML ↔ Markdown, then preview here |
| Escape text for HTML attributes | HTML entity encoder |
Markdown preview is not a Diff tool and does not interpret YAML frontmatter semantics.
Implementation Notes
These points match MarkdownTool in src/components/DataTool.tsx:
- Stack:
react-markdownwith a single remark plugin,remark-gfm. Not configured: rehype-highlight, remark-math, remark-emoji, rehype-raw, rehype-sanitize. - Styling: Tailwind Typography
prose prose-sm(including dark), not a separate Markdown CSS framework. - Views:
split/source/preview; default split; preference viausePersistentState. - Copy HTML uses
marked(GFM); the on-screen preview still usesreact-markdown+remark-gfm. Treat copied HTML as text until you sanitize it for your own page. - No colored syntax highlighting: language tags may appear as classes; the page does not colorize tokens.
- Emoji shortcodes are not expanded: use Unicode characters.
- Sample document: built-in Chinese GFM checklist sample to show tables and task lists on first paint—not lorem.
- Relation to this site’s blog: blog MDX serialization also enables
remark-gfm(pages/blog/[slug].tsx), so table dialect matches between posts and this tool. Blog content additionally follows MDX/JSX rules (a bare less-than sign in prose can break serialization)—a different path from this pure Markdown string preview.
FAQ
Can Markdown and HTML be mixed?
Many platforms allow HTML inside Markdown. This preview tool does not treat raw HTML in the source as an executable page fragment. For an HTML string, use the converter and sanitize before embedding on your own site.
What file extension?
Usually .md or .markdown. GitHub, GitLab, and similar platforms render .md in repositories.
Math support?
Neither standard Markdown nor this preview ships KaTeX/MathJax. Enable math on the destination platform or render after export.
Is data uploaded?
Preview runs locally in the browser. View preferences may land in local storage; on shared machines, clear site data or use a private window when finished.
Why does a “perfectly aligned” table break in preview?
Count separator pipes against the header column count, then check for unescaped | in cells. Misaligned spaces rarely matter; column-count mismatches do.
Further Reading
- HTML ↔ Markdown guide — Turndown / marked round-trip loss and table traps
- Markdown table generator guide — alignment syntax and generator behavior
- YAML ↔ JSON guide — serialization noise in fenced configs
- JSON formatting guide — normalize examples before code fences
- Text Diff guide — compare two Markdown or config revisions
- HTML entity encoder guide — escaping when text enters HTML
From the ToolVault developer notebook. The homepage collects more browser-local tools.
Related Tools
Related Articles
Online CSV to SQL Tool: Import Tabular Data into Databases
CSV to INSERT with empty cells → NULL, MySQL backticks or PostgreSQL quotes, BOM stripping, Markdown pipe escaping, and when to switch to COPY/LOAD instead.
HTML Table to JSON: How to Preserve Rows, Columns and Structure
Converting an HTML table from a web page to JSON — how to keep headers, handle merged cells and nested structure? Step-by-step with our HTML table to JSON tool.
Excel to JSON: Dates Become Numbers / Chinese Garbled — Fix
When converting Excel to JSON, dates turn into numbers like 44927, Chinese is garbled, empty cells vanish? Explains Excel serial dates and encoding pitfalls, with our Excel to JSON tool.