WYSIWYG Editor — Manual
Full reference for the WYSIWYG Editor: File menu, toolbar, dialogs, slash menu, snapshots, import/export formats, architecture, and limits.
Back to the overview: WYSIWYG Editor · Open the tool live: www.jpkc.com/tools/wysiwyg/
This manual describes the WYSIWYG Editor in full: the File menu and every toolbar function, the dialogs and bubble menus, the slash menu, the underlying TipTap extensions, all import and export formats, the architecture, and the technical limits. Button and menu names are quoted exactly as they appear in the interface.
Core concept
The editor is a single formatted writing surface (no split source pane). You type text, format it via the toolbar, the slash menu, or keyboard shortcuts, and the editor maintains a clean document model underneath. Technically it is TipTap 3 (opens in a new tab) — a headless rich text framework on top of ProseMirror — bundled into a finished application. A two-row toolbar sits above the surface, a status bar with document stats below it, and a badge at the top right shows the storage status.
As you start typing, live Markdown input rules (from the TipTap StarterKit) help out: # at the start of a line makes a heading, - a bullet list, 1. a numbered list, > a quote, ``` a code block, **bold** and *italic* set marks. The empty-editor placeholder hints at this: "Start writing… type "/" for commands, "# " for a heading, "- " for a list".
The toolbar works from the keyboard: it is one tab stop, and inside it the arrow keys, Home, and End move between buttons. On touch devices with a narrow screen, the two toolbar rows turn into horizontal swipe strips with ‹ › arrows at the edges; with a mouse or trackpad they wrap instead. Long menus adapt to the available height and scroll on their own.
The toolbar, row 1 — file, history, search, view
File menu
The File menu sits at the far left. It gathers every document-level way in and out, in four groups:
Document
- Open file (HTML / Markdown)… — opens a local file and replaces the current content. Accepted are
.html,.htm,.xhtml,.md,.markdown, and.txt; files ending in.md,.markdown, or.txtare read as Markdown, everything else as HTML. - Load from URL… — opens the Insert HTML from URL dialog: enter an absolute http(s) address, choose Replace the current document (the default) or Insert at the cursor position, and confirm with Fetch Content. The page's HTML is fetched through the server-side proxy (see architecture); relative links and image paths are rewritten to absolute URLs on the way in. Proxy errors (such as "too large" or "token expired") show up as a notice, not as text in your document.
- Snapshots… — the version store in your browser, see Snapshots.
- Edit HTML source… — the source editor, see HTML source.
- Clear document — empties the editor after a confirmation and deletes the auto-saved state. Before that, the editor takes an automatic snapshot, so you can bring the content back via Snapshots….
Save & export
- Save as HTML — saves the content as a standalone, light-themed HTML file with an embedded stylesheet, so the result is readable on white regardless of the editor theme. Code is statically syntax-highlighted, formulas are rendered with KaTeX, collapsible sections are expanded; headings get readable anchor IDs instead of internal identifiers ("Café Notes" becomes
cafe-notes, a second heading with the same textcafe-notes-2), and the<title>is the first heading. The document is always marked as English (<html lang="en">) — the same goes for Print… and Save HTML in the preview. For content in another language, adjust the attribute after saving so screen readers and hyphenation use the right language. - Export Markdown… — see Markdown.
- Export JSON (TipTap)… — see JSON.
- Save as PDF — produces a PDF via html2pdf (html2canvas + jsPDF): A4 portrait, 10 mm margins, double render resolution, page breaks that avoid cutting through a line where possible.
- Print… — opens a light-themed print window (a popup blocker may stop it; the tool tells you when that happens).
Copy to clipboard
- Copy as formatted text — puts the content on the clipboard as formatted text (
text/html) plus a plain-text version, so it pastes formatted into mail clients, Word, or Google Docs. Structure and formatting come along; code blocks only carry highlight.js class names and formulas the KaTeX markup — no stylesheet is copied with them. Whether code arrives in color and formulas properly typeset therefore depends on the target program; for a result with colors and typeset formulas, use Save as HTML. If the browser doesn't support this, only plain text is copied. - Copy as HTML — the document's clean HTML (with readable heading anchors).
- Copy as Markdown — the document as Markdown, without a detour through the export dialog.
Import
- Import Markdown… and Import JSON (TipTap)… — the import dialogs, described in the next two sections.
Every file the editor saves (HTML, Markdown, JSON, PDF) is named after the document's first heading, e.g. my-report.md — lowercase, accents stripped (ü becomes u, ß becomes ss), at most 60 characters. Without a heading, the first line of text serves as the template; if nothing usable is left, the file is called document.*. The same source supplies the <title> of the HTML file.
Markdown (Import / Export)
- Import Markdown… — opens the import dialog. At the top, Load from URL fetches raw Markdown from an address (through the same proxy as above); below, you paste Markdown into the text field or use Load .md file for a local
.md,.markdown, or.txtfile. URL and file both land in the text field first, so you can check and edit before committing. Import then replaces the editor content (with an automatic snapshot beforehand). - Export Markdown… — converts the current content to Markdown and shows it in a dialog; Copy puts it on the clipboard, Save .md file stores it as a file.
Markdown doesn't have to come through the dialog: when you paste plain text that looks like Markdown (headings, lists, fences, tables, **bold**, links …), the editor renders it straight into formatted content. That doesn't apply inside code blocks or when the clipboard already carries HTML; Ctrl+Shift+V pastes the text unchanged.
Round-trip details are under Markdown processing.
JSON (Import / Export)
- Import JSON (TipTap)… — loads a TipTap/ProseMirror document as JSON (pasted or via Load .json file). This is the editor's native, lossless document model — but only meaningful to this very editor, because it depends on the node schema. The editor checks the JSON against its schema before loading it; invalid or foreign JSON is rejected with "Invalid JSON - not a valid TipTap document", and the current content stays untouched.
- Export JSON (TipTap)… — outputs the current document as formatted JSON (Copy or Save .json file).
Snapshots
Snapshots… in the File menu opens the version store. Enter an optional name (up to 80 characters) and click Save current document to keep the current state; without a name, the first heading (or line of text) becomes the label. The list shows each snapshot's name, time, size, and whether it was taken automatically, along with Restore and a delete button.
- Automatic snapshots are taken before the editor replaces the document: opening a file (drag-and-drop included), a Markdown import, a JSON import, loading a URL in replace mode, Clear document, and before a Restore. If the state is identical to the latest snapshot, no duplicate is created. There is no snapshot for Apply in the HTML source editor or for loading a URL in Insert at the cursor position mode — there,
Ctrl+Zis your way back. - Limits: at most 20 snapshots are kept; beyond that, the oldest automatic ones go first. If browser storage runs short, the editor trims the list by the same rule.
- Restore replaces the content and can be undone with
Ctrl+Z.
Like auto-save, snapshots live only in local browser storage.
HTML source
Edit HTML source… shows the document's HTML in a code editor (ACE with syntax highlighting, indented by js-beautify; both are loaded on first use only). You can Copy the source, or edit it and take it over with Apply. The editor's schema applies: only markup the editor knows survives — scripts, classes, and custom styles are dropped. Apply replaces the whole document but takes no automatic snapshot; undo it with Ctrl+Z.
Clipboard and history
- Cut / Copy / Paste (
Ctrl+X/Ctrl+C/Ctrl+V) — within the editor, a paste keeps the exact inline/block context (a copied word doesn't become a new paragraph); external content is taken preferentially as rich HTML, otherwise as plain text. If the browser blocks the Paste button's clipboard access, useCtrl+V. - Undo / Redo (
Ctrl+Z/Ctrl+Y) — via TipTap's undo/redo history (UndoRedo).
Find / Replace
- Find (
Ctrl+F) and Find & Replace (Ctrl+H) open a search bar above the surface. It usesprosemirror-search, shows the match count, and highlights all matches. The shortcuts apply while focus is in the editor (or in fullscreen); elsewhere the browser's own search stays available. - Options: Case (case-sensitive), Word (whole words only), Regex (regular expression; an invalid pattern is flagged as "Invalid regex"). The Replace button reveals the replace row, where Replace swaps the current match and moves on, and Replace all swaps every match.
Enterjumps to the next match,Shift+Enterto the previous,Esccloses the bar.
Page width
A dropdown sets the width of the writing surface: Full width, Wide (1100 px), or Narrow (760 px) for a comfortable line length. The choice is remembered in the browser and affects only the view, not the export.
Editor theme
Three writing-surface themes: Dark, Light, Sepia. The choice is remembered in the browser. Important: this is only the look of the writing surface — preview, print, HTML, and PDF export are always light-themed so the result is readable everywhere.
Preview / view
- Show invisible characters — toggles whitespace and break markers.
- Table of contents — opens a side panel of all headings, numbered hierarchically (1, 1.1, 1.2 …); a click jumps to the spot. Headings inside collapsible sections count, the title of a collapsible section itself does not.
- Preview (Light) — shows the content read-only and light-rendered in a dialog, with its own Save HTML, Print, and PDF buttons.
- Toggle fullscreen — distraction-free fullscreen mode;
Escexits (if the search bar is open,Esccloses that first).
The toolbar, row 2 — formatting
Block type
A dropdown that switches the current block: Paragraph, Heading 1–Heading 6, Code block, Quote. The label shows the active block type.
Code language
Sets the syntax-highlighting language of the current code block (or creates one if the cursor is not inside one). Choices: Plain text plus 17 languages — HTML/XML, CSS, JavaScript, PHP, Python, Java, C, C++, C#, Ruby, Go, Rust, SQL, Bash, JSON, YAML, Markdown. Highlighting is done by lowlight wrapping the highlight.js engine (see Syntax highlighting).
Font family
Sets the font of the selection: Default font plus nine stacks (Arial, Times New Roman, Georgia, Courier New, Verdana, Trebuchet MS, Tahoma, Comic Sans MS, Monospace).
Inline marks
The inline marks: Bold (Ctrl+B), Italic (Ctrl+I), Underline (Ctrl+U), Strikethrough, Inline code, Subscript, Superscript. Active marks are highlighted in the toolbar.
Color & highlight
- Text color — a dropdown with eleven swatches (Red, Orange, Yellow, Green, Teal, Blue, Purple, Pink, Grey, Black, White), a Custom… color picker for anything else (it applies while you drag), and Remove. A color bar on the button shows the color at the cursor position.
- Highlight (
Ctrl+Shift+H) — marker-pen highlight in the default color. The small arrow next to it (Highlight color) offers six marker colors (Yellow, Green, Blue, Pink, Orange, Purple) and Remove highlight. - Clear formatting — removes all marks and resets blocks to paragraphs.
Lists
Bullet list, Numbered list, Task list (checkboxes, nestable).
Alignment
Align left / center / right and Justify for headings and paragraphs.
Insert
- Link (
Ctrl+K) — opens the link dialog with URL, Text (empty means the URL itself), and Open in a new tab (on by default). A bare domain such asexample.combecomeshttps://example.com, an email address becomesmailto:…; anchors (#…) and relative paths stay as they are. The dialog refusesjavascript:,vbscript:, anddata:links. With the cursor inside a link, the dialog edits that link and adds a Remove link button. URLs are linked automatically as you type or paste; clicking a link inside the editor doesn't open it. - Remove link — removes the link at the cursor position.
- Insert image — dropdown: From URL opens the image dialog with Image URL (http(s) or a path starting with
/), Alt text (leave empty only for purely decorative images), and Title (an optional tooltip); Upload (base64) embeds a local image file as base64. You can also drag and drop images into the editor or paste an image file from the clipboard. Resize an inserted image by its corner handles (aspect ratio is kept, minimum 40 × 20 px). - Table — Insert table (3×3 with header row) plus operations: Add column before/after, Delete column, Add row before/after, Delete row, Toggle header row, Merge / split cells, Delete table. Column widths are draggable.
- Horizontal rule — a horizontal divider.
- Collapsible section — an expandable
<details>block; the cursor lands right in the title (summary), with the content below. - Math (KaTeX) — Inline math ($…$) or Block math ($$…$$) open the Math (LaTeX) dialog: an Inline ($…$) / Block ($$…$$) switch, a LaTeX field, and a live KaTeX preview. Apply or
Ctrl+Enterinserts the formula. Clicking a rendered formula reopens it in the same dialog for editing (its type — inline or block — is then fixed). - Emoji — a searchable emoji picker (shows up to 120 matches). Alternatively, type
:in the text for shortcode autocomplete; classic emoticons such as:)are converted as well.
Bubble menus and drag handle
Small floating menus appear depending on context:
- Selection: with text selected — Bold, Italic, Underline, Strikethrough, Inline code, Link, Highlight, and Clear formatting.
- Link: with the cursor inside a link, the bubble shows the target address (a click opens it in a new tab) plus Edit link, Copy link address, and Remove link.
- Image: with an image selected — Alt (edit alt text and title), Original size (reset any resizing), and Remove image.
- Table: with the cursor inside a table, a bar appears above the table to add a row above/below, delete the row, add a column left/right, delete the column, toggle the header row, merge/split cells, and delete the table.
Hovering over a block reveals a drag handle on the left for moving the block.
Slash menu and keyboard shortcuts
Type / at the start of a line or after a space and the slash menu opens. Typing on filters the list (by title and by keywords such as todo, latex, or divider); arrow keys plus Enter or Tab pick an entry. Unfiltered, the menu shows the first twelve entries; Collapsible section and the two formula entries appear once you type something like /coll or /math. The entries: Text, Heading 1, Heading 2, Heading 3, Bullet list, Numbered list, Task list, Quote, Code block, Table (3 × 3 with header row), Image (opens the image dialog), Divider (horizontal rule), Collapsible section, Math block, and Inline math (both open the formula dialog). Inside code blocks and inline code, / stays an ordinary character — a path like /usr/bin triggers nothing.
The key shortcuts at a glance:
| Shortcut | Effect |
|---|---|
Ctrl+B / Ctrl+I / Ctrl+U |
bold / italic / underline |
Ctrl+Shift+H |
highlight |
Ctrl+K |
link dialog |
Ctrl+Z / Ctrl+Y |
undo / redo |
Ctrl+F / Ctrl+H |
find / find and replace |
Ctrl+Shift+V |
paste without Markdown conversion |
Ctrl+Enter |
apply the formula in the formula dialog |
/ |
slash menu |
: |
emoji autocomplete |
Esc |
close the search bar, or leave fullscreen |
The extensions at a glance
The editor bundles these TipTap extensions (the factual list from the bundle):
- StarterKit — base nodes and marks: paragraph, headings (H1–H6), bold, italic, underline, strikethrough, inline code, quote, bullet/numbered lists, horizontal rule, hard break, undo/redo (UndoRedo), and the Markdown input rules. (The built-in link and code block are disabled and replaced by the specialized versions.)
- Link — configured standalone (autolink with
httpsas the default protocol, link-on-paste, no open-on-click in the editor). - CodeBlockLowlight — code blocks with syntax highlighting.
- TextStyle, Color, FontFamily — text color and font.
- Highlight (multicolor), Subscript, Superscript.
- TextAlign — alignment for headings and paragraphs.
- TaskList / TaskItem — task lists (nestable).
- Table / TableRow / TableHeader / TableCell — tables (resizable).
- Image — images, base64 allowed, resizable by corner handles.
- Details / DetailsSummary / DetailsContent — collapsible sections.
- Typography — typographic substitutions (e.g. quotes, dashes).
- Mathematics — KaTeX formulas, inline and block.
- CharacterCount — word count (for the status bar).
- InvisibleCharacters — show invisible characters.
- FileHandler — drag-and-drop of images (as base64) and of HTML/Markdown files (opened as a new document); pasted image files are embedded as base64 too.
- Placeholder — placeholder text in the empty editor.
- Emoji — emoji nodes with
:shortcode:autocomplete and emoticon conversion. - TableOfContents — table of contents from the headings.
- prosemirror-search — find and replace.
- Suggestion — the foundation of the slash menu and the emoji suggestions.
- BubbleMenu — the four context menus (selection, link, image, table).
- DragHandle — the block drag handle.
Markdown import and export
Markdown is processed through an HTML round-trip using the project's established libraries:
- Import (Markdown → HTML): markdown-it (opens in a new tab) with
linkifyon (bare domains get linked too) and HTML pass-through, plus plugins for task lists, subscript (~x~), superscript (^x^), highlight (==x==), footnotes, and definition lists. YAML front matter at the top of the document is converted into ayamlcode block instead of being mangled. LaTeX math ($…$/$$…$$) is detected and inserted as formula nodes;$signs inside code are protected, and amounts like$5 and $10are not read as a formula. - Export (HTML → Markdown): Turndown (opens in a new tab) with the GitHub Flavored Markdown extension. ATX-style headings (
#), compact-bullets, fenced code blocks. Custom rules make sure the result re-imports as the same document:- Strikethrough as
~~x~~(a single~x~would read back as subscript), sub/superscript as~x~/^x^, formulas as$…$/$$…$$. - Highlight as
==x==; a highlight in another color as<mark style="…">. - Whatever Markdown can't express stays as inline HTML: underline (
<u>), text color and font (<span style>), centered, right-aligned, or justified paragraphs and headings (<p>or<h1>–<h6>withstyle="text-align:…"— so a centered heading comes out as HTML rather than## …), collapsible sections (<details><summary>with Markdown in between), and resized images (<img width>). - Tables:
|inside cells is escaped, and the export writes column alignment as:--/:-:/--:. On re-import, centered (:-:) and right-aligned (--:) columns survive; an explicitly left-aligned column (:--) falls back to the default alignment. - A
yamlcode block at the top of the document turns back into real---front matter. - Headings and links stay single-line.
- Strikethrough as
Export, re-import the result, and export again, and you usually get the same Markdown back — the exception is table columns marked left-aligned: :-- becomes --- on the second export.
Limits of the Markdown round-trip
- SVG images as
data:URLs don't survive the Markdown import (deliberately, for security, because a link to an SVG could run its scripts). They work through the HTML and JSON routes. Raster images (PNG, JPEG, GIF, WebP, BMP, ICO, AVIF) as base64 are preserved. - Footnotes and definition lists are flattened on import, because the editor has no nodes for them: footnote references become superscript numbers with a numbered list, definitions become
- **Term** — Definition. - Inline HTML in the export: underline, colors, alignment, collapsible sections, and image sizes come out as HTML. This editor reads that back in (as does any renderer with HTML pass-through); systems that filter HTML out of Markdown lose those formats.
- Markdown has no native syntax for sub/superscript and highlight — hence the
~x~,^x^, and==x==conventions, which not every Markdown renderer understands.
Syntax highlighting
Code blocks are color-highlighted — via lowlight, which wraps the highlight.js engine. In the live editor, TipTap draws the colors with ProseMirror decorations (view-only). Because those decorations do not appear in the serialized HTML, the tool re-highlights the code blocks statically with highlight.js for preview, print, export, and Copy as formatted text. The registered language set covers the 17 languages listed above; you pick a block's language via the Code language menu.
Status bar and auto-save
Below the surface, a status bar shows the document stats in the format "HTML: N bytes | N words | N blocks | ~N min read" (HTML byte size, word count, number of top-level blocks, estimated reading time at 200 words per minute); an empty editor reads "Empty document".
The content is saved automatically in local browser storage (one second after your last edit, and once more when you leave the page). On the next visit the editor restores it; that restore doesn't enter the undo history, so Ctrl+Z won't empty the restored document. The badge at the top right shows "Saved HH:MM". If storage is full (typically from many base64 images) or blocked, the badge turns red and a one-time notice suggests saving the document as a file.
Auto-save has one slot (the current document); you keep older states with snapshots. The browser also remembers the editor theme and page width.
Architecture and privacy
The editor runs almost entirely client-side:
- In the browser: all editing, the Markdown, JSON, and HTML export, copying, the PDF export, preview and print, the HTML source editor, and auto-save and snapshots. Your content is held only in local browser storage and never uploaded to a server.
- Server-side — only the URL fetch: Load from URL… in the File menu and Load from URL in the Markdown import fetch the remote page through a server-side JPKCom proxy, because the browser cannot load remote pages directly due to CORS. The target page thus sees a request from the JPKCom server (with its user agent), not your IP address.
The two server-side endpoints (a fetch proxy and a token endpoint) are not a public API you can call yourself — they are used exclusively by the tool's JavaScript and hardened against abuse:
- Token authentication: before each fetch the tool obtains a fresh token built from two SHA-256 components plus a timestamp, valid for at most five minutes. The token endpoint checks the referer and a daily-rotating secret.
- SSRF protection: private, local, and internal IP addresses are blocked, and checked again after every redirect; HTTP/HTTPS only, and only ports 80, 443, 3000, 5000, 8000, 8008, 8080, and 8443 — an address on any other port is rejected with "Invalid URI".
- Limits: maximum response size 950 KB, timeout 10 s per request (5 s to connect), at most five redirects totalling 30 s, maximum execution time 20 s.
- Rate limit: at most 120 fetches per minute per IP address; beyond that, the proxy answers with a readable "Too many requests" message.
There is an optional Expert Mode with a local proxy (http://127.0.0.1:<port>): instead of going through the JPKCom server, a self-hosted local proxy fetches the page. Setup is advanced and not needed for normal use.
When loading foreign content (URL, file, Markdown, paste), the editor parses the HTML in an inert document, so scripts or event handlers inside it don't run; anything the editor doesn't know is dropped when it takes the content over anyway.
Operating limits — in brief
- One document, no collaboration. There is one auto-saved working state plus up to 20 snapshots, all in the browser. Clearing browser data means losing content and snapshots — export important states as a file first.
- base64 images bloat the document. Images embedded by upload, drag-and-drop, or paste land as base64 directly in the HTML, in local storage, and in every snapshot; many or large images can exceed the storage quota. Resize images first (see tips).
- JSON only from this editor. JSON import is meant only for JSON this editor exported; foreign JSON is rejected.
- HTML is reduced to the schema. When opening a file, loading a URL, or applying the source editor, only markup the editor knows survives (no scripts, classes, or custom styles).
- URL fetch: public http(s) addresses on ports 80, 443, 3000, 5000, 8000, 8008, 8080, or 8443 only, max 950 KB, no localhost/intranet, at most 120 fetches per minute.
- Emojis: only those with a native Unicode glyph (up to Unicode 15.0); newer or image-only emojis are removed for rendering and privacy reasons.
For the introduction and target audiences see the overview, for workflows the examples, and for tricks the tips & tricks. You can try everything directly in the tool.