npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vemonet/typodown

v0.0.5

Published

A Typora-like WYSIWYG markdown editor for the web. Renders GitHub Flavored Markdown inline and reveals the raw markdown syntax on the block under the cursor.

Readme

🖋️ Typodown

npm license

An embeddable markdown editor inspired by Typora.

There is no separate preview pane: the markdown is rendered inline in the text you edit, and the markdown source stays the only source of truth. Move the caret into a heading, bold run, code span or link and its raw markers (#, **, `) show up for that construct only.

⚡️ Live demo →

Features

  • Edit the rendered markdown directly, no preview to keep in sync and no rich-text mode.
  • Only the construct holding the caret shows its raw syntax, everything else stays rendered.
  • GitHub Flavored Markdown, with syntax highlighting, GFM alerts (> [!NOTE]), checkbox lists, editable tables, mermaid diagrams, and LaTeX maths (inline $...$ and block $$...$$, rendered with KaTeX).
  • The usual shortcuts: Ctrl/⌘+B bold, Ctrl/⌘+I italic, Ctrl/⌘+K link, Tab / Shift+Tab indent / outdent, Ctrl/⌘+Z undo / redo.
  • Built on CodeMirror 6.

Install

npm i --save @vemonet/typodown

Usage

import { createTypodown } from "@vemonet/typodown";
import "@vemonet/typodown/style.css";

const editor = createTypodown(document.getElementById("editor")!, {
  value: "# Hello",
  theme: "auto",
  placeholder: "Write some markdown...",
  tabSize: 4, // spaces per indent level (Tab / Shift+Tab), defaults to 4
  onChange: (markdown) => console.log(markdown),
});

editor.getValue(); // read the current markdown
editor.setValue("new **content**");
editor.setTheme("dark");
editor.focus();
editor.destroy();

Themes

Typodown includes light (GitHub Light), dark (GitHub Dark), dracula, nord, solarized-light, and solarized-dark. auto switches between the GitHub themes using the operating-system preference. A theme can be changed at any time without recreating the editor:

editor.setTheme("dracula");

To provide a custom theme, pass any name and define its CSS variables on the editor's data-td-theme attribute. Variables omitted here keep the default GitHub Light value. Syntax variables are optional too.

editor.setTheme("rose-pine");
.typodown[data-td-theme="rose-pine"] {
  --td-bg: #191724;
  --td-fg: #e0def4;
  --td-muted: #908caa;
  --td-faint: #6e6a86;
  --td-border: #403d52;
  --td-border-muted: #26233a;
  --td-heading-border: #403d52;
  --td-link: #c4a7e7;
  --td-code-bg: rgba(110, 106, 134, 0.2);
  --td-code-fg: #e0def4;
  --td-block-bg: #1f1d2e;
  --td-code-block-bg: #1f1d2e;
  --td-table-header-bg: #26233a;
  --td-table-alt-bg: #1f1d2e;
  --td-selection: rgba(196, 167, 231, 0.3);
}

From plain HTML, no bundler

A standalone UMD build (CodeMirror and Lezer bundled in) is available as dist/index.umd.js (e.g. on unpkg/jsDelivr), exposing a Typodown global. It's larger than the npm package (~189 KB gzipped, vs ~16 KB when CodeMirror is shared with the rest of your bundle), since it can't dedupe those dependencies against anything else on the page:

<link rel="stylesheet" href="https://unpkg.com/@vemonet/typodown/dist/style.css" />
<script src="https://unpkg.com/@vemonet/typodown/dist/index.umd.js"></script>

<div id="app"></div>
<script>
  const editor = Typodown.createTypodown(document.getElementById("app"), {
    value: "# Hello",
  });
</script>

Options

| Option | Type | Default | Description | | ------------------ | --------------------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | | value | string | "" | Initial markdown content. | | theme | Theme | "auto" | Bundled theme name or a custom data-td-theme name. auto follows the OS preference. | | placeholder | string | "" | Shown while the document is empty. | | spellcheck | boolean | false | Enable the browser's native spellcheck. | | html | boolean | true | Render raw HTML blocks/tags as live widgets. | | joinSoftBreaks | boolean | true | Render a paragraph hard-wrapped in the source as one flowing paragraph. Off keeps every source line on its own visual line. | | tabSize | number | 4 | Spaces per indent level: what Tab inserts and Shift+Tab removes. Also settable later with editor.setTabSize(n). | | toolbar | "auto" \| "shown" \| "hidden" | "auto" | Floating formatting toolbar. auto starts visible on small screens and hidden on large ones; a floating button toggles it either way. | | onChange | (value: string) => void | | Called whenever the content changes. | | getClipboardText | () => string \| Promise<string> | navigator.clipboard.readText | Read the clipboard for the Ctrl/⌘+K link shortcut. Provide it where the Clipboard API is blocked (e.g. VSCode webviews). |

LANGUAGES and matchLanguages are also exported for standalone use with the fenced-code language picker.

CommonMark compatibility

Since Typodown is an overlay on the markdown source rather than a markdown-to-HTML renderer, "CommonMark compliance" is really a property of the parser it is built on rather than of the editor. To put a number on it anyway, tests/commonmark-spec.test.ts runs every example in the official CommonMark spec suite (652 examples) through a minimal reference HTML renderer built for testing only (tests/commonmark-html.ts) and diffs the output against the spec's expected HTML.

Current result: 612/652 (93.9%). The remaining gaps are parser-level, so the live-preview layer cannot work around them:

  • Tabs (10/11 failing): tab characters aren't expanded to the CommonMark-specified 4-column stops for indentation, so a leading tab doesn't trigger indented code the way 4 spaces would.
  • Raw HTML edge cases: a handful of unusual but valid inline tags (unclosed angle brackets spanning lines, HTML comments containing --) aren't recognized as HTML and get escaped as text instead.
  • Reference links: a few corner cases (labels containing nested unresolved brackets, Unicode case-folding like ẞ/SS, ambiguous adjacent reference forms) resolve differently than the spec's backtracking algorithm.

How it works

Typodown never renders the markdown to HTML: it is a live-preview overlay on the markdown source itself.

Markdown is parsed with @lezer/markdown (the same incremental CommonMark parser @codemirror/lang-markdown uses) configured with its GFM extension bundle (tables, task lists, strikethrough, autolinks).

CodeMirror 6 owns the document, caret, selection, undo history and viewport virtualisation, and the markdown text in its buffer is the only source of truth. A ViewPlugin (inline and line decorations) and a StateField (block-level replacements like tables) walk the Lezer syntax tree over the visible viewport on every change, producing Decorations that style each construct and hide its raw syntax marks (**, #, backticks, [...](...)). When the selection overlaps a construct, its marks are left visible instead, so the source stays editable right where the caret is.