Markdown Editor & Preview_
Write on the left and watch it render on the right. The toolbar toggles — press Bold on bold text and the asterisks come off again — and with nothing selected each button acts on the word under the caret. Keyboard shortcuts match the ones you already use.
Your draft is kept in this browser's own storage and nowhere else, so closing the tab does not lose it and no account is involved. Turn that off with one checkbox, and clear it with one button.
- Input
- Markdown typed, pasted or restored from the draft this browser holds.
- Output
- A live rendered preview, plus the source to copy or download as a .md file.
- Processing
- Rendered in this tab on the GitHub flavour, sanitised before it reaches the preview, and the preview frame cannot execute anything.
- Limits
- A draft lives in this browser only. Clear the site's data, use a private window, or open it on another machine and it is not there.
- Toggling, not inserting
- Every formatting button removes its own markup when it is already applied. A bold button that only inserts asterisks gives you ****word**** on the second press, which is the commonest defect in editors of this kind.
Where your draft actually lives
In this browser, under a name you can look up
The draft is written to this browser's local storage under the key toolkit.markdown-editor.draft. You can open your developer tools and read it. Nothing is sent anywhere, there is no account, and there is no copy on any server — which also means the draft is tied to this browser on this machine. A different browser, a private window, or another computer will not have it, and clearing site data removes it. That is the honest trade for not asking you to sign in.
Why the preview is a frame that cannot run anything
An editor invites you to paste things, and a pasted Markdown file can legally contain <script> — the format allows embedded HTML and parsers hand it on untouched. So the preview is running somebody else's markup by design. Two independent things stop it mattering. The markup is cleaned before the preview receives it, and the preview sits in a frame whose sandbox omits allow-scripts, so nothing inside can execute regardless of what the cleaner did or missed. The frame does carry allow-same-origin, which is how this page measures the rendered height to keep the two panes in step. That token is only a hazard next to allow-scripts, since together they let a frame drop its own restrictions — and there is no script here to attempt it. The Markdown to HTML converter lists exactly what the cleaner strips.
The toolbar toggles, which is harder than it sounds
"Already bold" has three shapes and all of them have to come undone. The asterisks can be inside your selection, if you dragged across them; outside it, if you double-clicked the word between them; or there may be no selection at all, in which case the word under the caret is what you meant. Each case leaves the caret somewhere different afterwards, and getting that wrong sends your next keystroke into the markup. There is a fourth trap: a single * pressed on **word** must not strip one asterisk from each side, because that quietly turns bold into italic. Markdown counts these markers in runs, so the rule is parity, not presence.
Scroll sync is proportional, and deliberately so
Tying source line 40 to the element it produced sounds better and cannot be done reliably: one line can become a heading and a paragraph, twenty lines of fenced code become a single element, and a link reference definition becomes nothing at all. Anchored syncing therefore jumps when the map is wrong, which is most disruptive exactly while you are typing. Proportional scrolling never surprises you, and it is honest about being an approximation.
Write, format, keep
- 01Type or paste Markdown on the left. The preview re-renders as you go, and the counts under the panes update with it.
- 02Select some text and use the toolbar, or the shortcut. Press the same button again to take the formatting off — with nothing selected it works on the word your caret is in.
- 03Leave "Keep a draft here" on and your work survives closing the tab. The line beside it tells you when it was last written; Restore pulls it back if you have overwritten the pane.
- 04Copy the source, or download it as a .md file. For HTML output with control over flavour and raw-HTML handling, the Markdown to HTML converter owns that contract.
Four documents and what the editor does for them
A README before it goes in the repo
Tables and task lists need checking against what GitHub will show.
GitHub, with tables and task lists
Download as README.md
A long post written over several sittings
The tab gets closed; the draft does not go with it.
toolkit.markdown-editor.draft
Restore, with the age shown
A document somebody emailed you
It may contain raw HTML. Paste it and nothing can run.
scripts, on* handlers, javascript: URLs
sandbox without allow-scripts
Notes that need a table you cannot remember the syntax for
The alignment row is the part everyone gets wrong.
Table
| --- | --- | --- | with the caret in cell one
Keyboard shortcuts
| Shortcut | Does | With nothing selected |
|---|---|---|
Ctrl/Cmd + B | Bold, and unbold | Acts on the word under the caret |
Ctrl/Cmd + I | Italic | Acts on the word under the caret |
Ctrl/Cmd + E | Inline code | Acts on the word under the caret |
Ctrl/Cmd + K | Link, caret lands in the parentheses | Uses the word as the label |
Ctrl/Cmd + H | Cycle heading level, 1 to 6 then off | Applies to the current line |
Ctrl/Cmd + Q | Blockquote | Applies to the current line |
Ctrl/Cmd + L | Bulleted list | Applies to the current line |
Ctrl/Cmd + Shift + O | Numbered list, renumbered from 1 | Applies to the current line |
Ctrl/Cmd + Shift + X | Strikethrough | Acts on the word under the caret |
Ctrl/Cmd + S | Write the draft now rather than waiting | — |
Ctrl+P, Ctrl+F, Ctrl+A, Ctrl+Z and the clipboard keys are deliberately left to the browser — an editor that steals Find is worse than one without shortcuts.
What each toolbar button inserts, and what it removes
| Button | Inserts | Pressed again |
|---|---|---|
| Bold | **text** | Removes both pairs |
| Italic | *text* | Removes them — and never mistakes **bold** for two italics |
| Heading | # then ## and so on | Cycles to level 6 then back to plain text |
| List | - on every selected line | Strips it from every line that has it |
| Numbered list | 1. , 2. , renumbered | Strips the numbering |
| Table | A header row, an alignment row and two blank rows | Inserts another — tables do not toggle |
| Code block | A fenced block around the selection | Removes the fences, from inside or outside the selection |
A selection that is only half formatted gets the markup added throughout rather than half toggled, because predictable beats clever when you drag across a partly-formatted list.
Getting more out of it
- Double-click a word and press the shortcut — that selects the text between the markers, which the toolbar handles as already-formatted and removes.
- Drag across several lines before pressing a list or quote button; every line in the selection gets the prefix in one go.
- Use the Table button rather than typing pipes. The alignment row is the part that decides whether it renders at all, and it is easy to miscount.
- Turn off "Keep a draft here" on a shared or public machine. The draft is only in this browser, but this browser is the one somebody else is about to use.
- Keep sync scrolling on for long documents and off when you are working on one section — a jumping preview is more distracting than a still one.
- For a word count with reading time, sentence and paragraph breakdowns, the word counter goes much further than the running total here.
Things worth knowing before you rely on it
A draft in this browser is not a backup
It lives in local storage on this machine, in this browser profile. A private window, a different browser, another computer, or clearing site data all mean it is not there. It is protection against closing a tab, not against losing a laptop — download anything you would be sorry to lose.
The preview renders GitHub flavour with sensible defaults
Task lists tick, tables lay out, autolinks and strikethrough behave, and embedded HTML is cleaned rather than displayed as source. If you need CommonMark instead, or raw HTML shown as text, or a whole document rather than a fragment, those are conversion options and they live on the Markdown to HTML converter.
Markdown flavours disagree about more than tables
A single newline inside a paragraph is a line break on GitHub comments and merely a space in CommonMark. Underscores inside a_word emphasise in some parsers and not others. Nested list indentation is the classic one. What renders here is what a GitHub-flavour parser produces, which is not universally what your destination will do.
Sanitising is not the same as validating
The preview shows you what survives the sanitiser, which is what you would get if you pasted the output somewhere sensible. It is not a guarantee about what a different renderer will do with your raw HTML — some destinations strip more, some allow more. If the document must be safe in a specific place, test it there.
Very large documents are refused, and here that protects the draft
Past 2 MB the editor stops rather than struggling. Five representations of your document are alive together while a render runs, and a tab that exhausts its memory takes the unsaved draft with it — which is a worse outcome in a writing tool than in a converter. The refusal happens before any parsing starts, so nothing has been spent by the time you see it.
Rendering, storage and the sandbox
- Flavour
- GitHub flavour: task lists render, tables render, autolinks and strikethrough work. A lone newline inside a paragraph stays a space, which is how GitHub treats a committed file rather than a comment box
- Raw HTML
- Cleaned rather than shown as text, using the policy the Markdown to HTML converter documents in full — that page owns the conversion contract, and both run the same code
- Preview isolation
- A frame whose
sandboxomitsallow-scripts, so nothing in a previewed document executes.allow-same-originis present so the page can measure the rendered height for scroll sync — that permission only creates an escape route when paired withallow-scripts, which is absent - Draft storage
- This browser’s local storage, under
toolkit.markdown-editor.draft, holding a version number, the text and a timestamp. A stored value that is corrupt, truncated or from a future version is discarded rather than thrown, so a bad entry cannot stop the editor opening - Toolbar
- Every inline button toggles, detecting markers inside the selection, outside it, or around the word under a bare caret. Single-character markers use run parity, so italic never strips one asterisk off a bold pair
- Scroll sync
- Proportional between the two panes. Line-to-element anchoring is not attempted because no reliable map exists — one source line can produce several elements, or none
- Size limit
- 2 MB, refused before the parser is loaded. The document exists as source, tokens, HTML, a sanitiser DOM and a preview DOM at the same time
- Scope
- The conversion contract — flavour switching, escaped raw HTML, whole-document output — belongs to Markdown to HTML; going the other way is HTML to Markdown
- Network
- None from tool code. A test sweep calls every function this page uses with
fetchandXMLHttpRequestreplaced by stubs that throw, so a stray request fails the build instead of shipping. Disconnect from the network and the page still works.
Questions about writing Markdown here
Where is my draft stored?
In this browser’s local storage, under the key toolkit.markdown-editor.draft — you can open developer tools and read it yourself. There is no account and no server copy, which is also the limitation: the draft belongs to this browser on this machine, so another browser or a cleared cache will not have it. Download anything you would be sorry to lose.
Is it safe to preview a document somebody sent me?
Yes, and it does not rest on a single filter being perfect. The markup is cleaned on the way to the preview, and the preview frame withholds allow-scripts, so nothing in the document can run whatever survived the cleaning. The frame does allow same-origin access, purely so this page can read its height and keep the panes aligned; that permission opens an escape route only when scripts are permitted too, and they are not. The work is JavaScript running in this tab. Every function it calls is covered by a test that stubs fetch and XMLHttpRequest to throw, so a request that slipped in would break the build rather than reach a server — and you can confirm it for yourself by disconnecting and carrying on.
Why does the bold button sometimes remove formatting?
Because it toggles. If the selection is already bold — whether the asterisks are inside your selection, just outside it, or around the word your caret is in — pressing Bold takes them off. A button that only ever inserted markers would give you ****word**** the second time you pressed it, which is the commonest defect in editors of this kind.
Which Markdown flavour does the preview use?
GitHub flavour. Task lists, tables, autolinks and strikethrough all behave as they would in a repository, and a lone newline mid-paragraph stays a space rather than becoming a break — which is how a committed file renders, not how a comment box does. To switch to CommonMark or change how raw HTML is handled, use the Markdown to HTML converter, which owns those options.
Can I get the HTML out of this page?
This page hands you the Markdown — copy it, or download it as a .md file. The HTML is the deliverable on Markdown to HTML, which lets you choose fragment or whole document, pick the flavour, and decide whether raw HTML is sanitised or shown as text. Both pages run the same renderer, so the preview here and the output there agree.
Do the shortcuts clash with my browser?
Not with the ones that matter. Ctrl+F, Ctrl+P, Ctrl+A, Ctrl+Z and the clipboard keys are all left alone. Ctrl+S is claimed deliberately — it writes the draft immediately, which is what pressing it in a writing tool is meant to do.
Why does the preview scroll roughly rather than exactly?
Because an exact mapping does not exist. One source line can render as several elements, a twenty-line code fence renders as one, and a link reference definition renders as nothing. Anchoring to lines therefore jumps whenever the guess is wrong, which is worst while you are typing. Proportional scrolling is approximate and never surprising.