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

@docs.plus/extension-mermaid

v2.3.0

Published

Tiptap extension that draws Mermaid code blocks as live SVG diagrams with Pele, loaded on demand

Readme

@docs.plus/extension-mermaid

docs.plus Version Downloads License Discord

Tiptap extension that draws Mermaid code blocks as live SVG diagrams. The source stays on top, and the diagram redraws under it as you type.

Diagrams are drawn by Pele, the Mermaid renderer by Steph Ango (@kepano), CEO of Obsidian. MIT licence.

Open in StackBlitz

Why use it

  • The diagram follows the text. The SVG redraws 300 ms after you stop typing, for local and remote edits. A mistake names its line and column, and the last good diagram stays in view.
  • Charts, not only flowcharts. Pele detects and draws 33 diagram types, such as sequence, Gantt, pie, radar, sankey, XY chart and mind map. See the Gallery.
  • Drawn by Pele, loaded on demand. Your bundler emits Pele as separate chunks, and one chunk loads per diagram type. mermaid.js is not a dependency. Pele's speed claims and our own timing, with their limits, are in About Pele.
  • Size limits measured on real phones. A diagram over 10,000 characters or 250 arrows (edges) shows a message instead of drawing. Larger ones took more than 200 ms on a real Android phone or iPhone. The numbers are in Measured on real phones.
  • Readers see the diagram, writers see both. The Hide source button folds the text away. The fold option sets it up. Read-only editors start folded. Syntax and Copy sit beside it, in the head row above the source.
  • No new node, and a plain fence in storage. A diagram is a standard codeBlock with language: 'mermaid'. The document holds a mermaid fence, as on GitHub, GitLab and Obsidian, and never the SVG. Removing the extension leaves plain code blocks. Yjs merges the source per character.
  • Light and dark from your page. The default colours follow color-scheme. Pele's --pele-* variables, or the theme option, set your own.
  • Safe defaults, with one gap. Pele escapes diagram text. Links and remote images are off, and size limits cap the work. The SVG is not sanitized unless you pass sanitize, so pass it for sources you do not trust.

Install

npm install @docs.plus/extension-mermaid

Or use pnpm add @docs.plus/extension-mermaid, yarn add @docs.plus/extension-mermaid, or bun add @docs.plus/extension-mermaid.

Requires @tiptap/core ^3.32.2 and @tiptap/pm ^3.32.2 (Tiptap 3.x). They are peer dependencies. Some package managers do not install peers for you, so this line is always safe to run: npm install @tiptap/core@^3.32.2 @tiptap/pm@^3.32.2. Keep every @tiptap/* package in your app on the same version.

Upgrading from 2.2.0 to 2.3.0? The Tiptap peer floor rose from ^3.31.3 to ^3.32.2. Move @tiptap/core, @tiptap/pm and your other @tiptap/* packages first, then update this package. Most apps need no other change. Two things behave differently for an app with its own codeBlock node view:

  • A plugin nodeViews.codeBlock that ranks below this one now gets every block that is not mermaid. Its update must return false when a block's language changes to or from mermaid.
  • An app with its own addNodeView on codeBlock can now see the development warning. To draw diagrams there, call mermaidNodeView.

The Changelog has the full list.

This package imports no React, Vue, or Next.js code. Use it from a plain page, Vite, React, Vue, Svelte, Next.js, Nuxt, or SvelteKit. Create the editor in the browser.

React Native has no DOM. Load the editor in a web view.

Installs one runtime dependency: pele (1.8.0, pinned exactly), the renderer. The package loads Pele with a dynamic import(), so your bundler emits it as separate chunks. Nothing loads from a CDN. For CSP, see Content Security Policy.

Import the stylesheet @docs.plus/extension-mermaid/styles.css. The fold control, the head and the actions need it.

Quickstart

Open in StackBlitz

Run this Quickstart in your browser first, with nothing to install. The app lives in examples/vanilla.

The snippet also imports @tiptap/starter-kit. Its codeBlock node holds each diagram. Add it with npm install @tiptap/starter-kit@^3.32.2 when your app has none yet.

Your page needs color-scheme: light dark in its CSS, such as :root { color-scheme: light dark; }. Without it, diagrams keep the light colours in dark mode.

import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'
import { Mermaid } from '@docs.plus/extension-mermaid'
import '@docs.plus/extension-mermaid/styles.css'

// The page needs <div id="editor"></div> and `color-scheme: light dark`.
const editor = new Editor({ extensions: [StarterKit, Mermaid] })
editor.mount(document.querySelector('#editor')!)
editor.commands.setContent(
  '<pre><code class="language-mermaid">flowchart LR\n  A[Write] --> B[See it]</code></pre>'
)

You should see the source with a two-box flowchart under it. Edit the source, and the diagram redraws after you stop typing.

Caveats

  • Only the exact language mermaid draws. A fence tagged Mermaid with a capital M stays plain code. Markdown keeps all the text after the backticks as the language, so ```mermaid title stays plain code. In HTML, that text becomes two classes, and the parser reads only language-mermaid. So the same block becomes a diagram after an HTML round trip. This follows from how the two parsers read the language, not from this package. Tag the fence mermaid alone.
  • The editor needs a codeBlock node. Without one, nothing draws and insertMermaid returns false.
  • A host addNodeView on codeBlock wins. It replaces the diagram view, for example CodeBlockLowlight.extend({ addNodeView }). Call mermaidNodeView in that view to keep diagrams. In development, the console warns once per editor: [extension-mermaid] Another node view owns codeBlock…. The check reads process.env.NODE_ENV, so without a global process it stays off. The check changes only whether the warning shows. It never changes which view draws.
  • Among plugin views on codeBlock, the first one wins. A higher extension priority comes first. At equal priority, the extension listed last comes first. So extensions: [Mermaid, Other] lets Other take every block, and no diagram draws. A plugin view is a nodeViews.codeBlock prop on a ProseMirror plugin. This view hands every block that is not mermaid to the next plugin view. A plugin view that comes before this one takes mermaid blocks too, so no diagram draws. In development, the console shows the same warning. To fix it, list Mermaid after the other extension, or give Mermaid a higher priority. Or call mermaidNodeView in that plugin view through a wrapper, as Use it in a plugin view shows.
  • Without styles.css, the fold control, the head and the actions render unstyled, and Pele's own error box shows. Add the stylesheet. Or set fold: false, helpLink: false and copy: false, and copy the three rules from Without styles.css.
  • The default colours need color-scheme. They use light-dark(). Set color-scheme: light dark on your page, or the light colours always show.
  • Pele has no time limit. limits is the only cap on its work, so raise it with care. edges counts arrows in flowchart and agentflow (a Pele diagram type) only. See Security.
  • The SVG is not sanitized by default. Pass sanitize when sources come from people you do not trust. See Sanitizing the SVG.

The full list, with the reason for each, is in Caveats.

Common tasks

Add a toolbar or slash item

editor.chain().focus().insertMermaid().run()

The command inserts a four-line flowchart and puts the caret at the end of the source. Gate the button with editor.can().insertMermaid(). It does not check that a diagram can draw. Read the active state with editor.isActive('codeBlock', { language: 'mermaid' }). See Commands.

Writers can also type ```mermaid and then a space or Enter. The code block input rule makes a diagram block, and it matches lowercase only. A Markdown mermaid fence loads as a diagram when your editor parses Markdown. This package does not load a Markdown parser. Install one with npm install @tiptap/markdown@^3.32.2, then add Markdown next to Mermaid:

import { Markdown } from '@tiptap/markdown'

const editor = new Editor({ extensions: [StarterKit, Mermaid, Markdown] })
editor.commands.setContent('```mermaid\nflowchart LR\n  A --> B\n```', { contentType: 'markdown' })

Change the size limits

Mermaid.configure({ limits: { characters: 20000 } })

A missing field keeps its default, so edges stays 250 here. Each diagram block is checked on its own.

  • characters is the source's JavaScript length, spaces and accTitle lines included. A source of exactly the limit draws. Most emoji count 2, a flag counts 4, and a family emoji counts 11. Measure with source.length.
  • edges counts each link Pele draws. A chain A --> B --> C is 2. A --> B & C is 2, and A & B --> C & D is 4. <-->, -.->, ==>, --- and the invisible ~~~ count 1 each.
  • Only flowchart and agentflow have an edge count. Agentflow is a Pele diagram type. Other types, such as sequence, have only the characters limit.
  • A block over a limit shows "This diagram is too large to draw." and is never drawn. onStateChange reports state: 'error' with error.code 'limit'. If the block drew before, the last good diagram stays, dimmed. The dimming needs styles.css, or the third rule in Without styles.css.
  • No limit covers the whole document. A limit has no false setting. Infinity lifts it, and 0 blocks every diagram. Pele has no time limit, so lift or raise a limit only for sources you trust.
  • Pele has fixed caps of its own, such as the size of the drawn SVG. They also report 'limit', and limits does not change them.

See Options.

Sanitize the SVG

import DOMPurify from 'dompurify'

Mermaid.configure({
  sanitize: (svg) =>
    DOMPurify.sanitize(svg, {
      USE_PROFILES: { svg: true },
      ADD_ATTR: ['role'],
      FORBID_TAGS: ['style', 'a', 'image', 'use'],
      FORBID_ATTR: ['href', 'xlink:href'],
      RETURN_DOM_FRAGMENT: true
    })
})

sanitize must return a DOM Node, so keep RETURN_DOM_FRAGMENT: true. A returned string shows as plain text, not as a diagram. The package does not depend on DOMPurify. The attributes that must survive are listed in Security.

Report slow renders and load errors

Mermaid.configure({
  onStateChange({ state, error, durationMs }) {
    if (state === 'load-error') console.warn('Mermaid renderer did not load', error?.message)
    if (durationMs !== null && durationMs > 200) console.warn('Slow diagram', durationMs)
  }
})

With the built-in view, a block shows a spinner under the source while Pele loads. After a load-error, it shows "Could not load the diagram renderer." and a Try again button. durationMs covers Pele plus the sanitizer. It is null for every state except ready and error. See onStateChange.

Gallery

Each block is a plain mermaid fence, drawn with the default colours. Each screenshot has a light and a dark version, and follows your system preference.

Documentation

| Guide | What it covers | | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | API reference | Options, commands, states, onStateChange, fixed behaviour, class names, TypeScript exports, and the full caveats list | | Guide | Theming, source folding, the view slot, accessible names, syntax highlighting, and your own code block view | | Security | Untrusted sources, limits, sanitizing the SVG, and CSP | | About Pele | What Pele is, how this package uses it, and the credit | | Changelog | Every release and its breaking changes | | For AI coding agents | This README as plain Markdown for your agent. The docs are also on Context7 |

Part of docs.plus

This extension is built for and maintained by docs.plus. docs.plus is a free, real-time collaboration tool that lets communities organize knowledge hierarchically, with a chat thread on every heading. docs.plus runs these packages from source in production, so every release is exercised there before it reaches npm.

Contributing

Bug reports and PRs welcome. Setup, test commands, and the playground harness live in CONTRIBUTING.md.

License

MIT — see LICENSE.