Five publishable Tiptap extensions for docs.plus. The five packages share major version 2 under the @docs.plus npm scope. Release policy links the tracker that holds the npm status of each one.
Pick the package for the job, install it, and run its Quickstart.
| Package | What it does for you |
|---|---|
extension-hyperlink |
Turns typed URLs, emails, and E.164 phone numbers into links, with optional popovers to create, preview, and edit them. |
extension-hypermultimedia |
Embeds images, audio, video, YouTube, Vimeo, SoundCloud, Spotify, X, and Loom, each with a caption and a media toolbar. |
extension-indent |
Makes Tab indent text and Shift-Tab remove the indent, while lists and tables keep their own Tab behavior. |
extension-inline-code |
Formats text as inline code when you type it between backticks or press Mod-e, and adds no extra character to the document. |
extension-placeholder |
Shows hint text in the empty textblock at the cursor, and its cost does not grow with document length. |
Each package README is a short start page, and the detail lives in the docs/ folder of that package.
The table below adds the CSS export and the clean-room port of each package.
| Package | Description | CSS export | Clean-room port |
|---|---|---|---|
extension-hyperlink |
Hyperlink mark, autolink, optional prebuilt popovers, dangerous-scheme gate | ./styles.css |
5173 |
extension-hypermultimedia |
Nine media nodes: image, audio, video, YouTube, Vimeo, SoundCloud, Spotify, X, Loom | ./styles.css |
5174 |
extension-indent |
Tab / Shift-Tab literal indent with a context allowlist | none | 5175 |
extension-inline-code |
Inline code mark (Mod-e, backtick rules) |
none | 5176 |
extension-placeholder |
Hint text in the empty textblock at the cursor; cost tracks cursor depth, not document length | none | 5177 |
Each package README has an Open in StackBlitz button. It runs that package's Quickstart in the browser, with nothing to install.
npm install @docs.plus/extension-hyperlinkOr use pnpm add @docs.plus/extension-hyperlink, yarn add @docs.plus/extension-hyperlink, or bun add @docs.plus/extension-hyperlink.
Use the matching package name from the table above (@docs.plus/extension-hypermultimedia, @docs.plus/extension-indent, and so on).
Requires @tiptap/core ^3.31.3 and @tiptap/pm ^3.31.3 (Tiptap 3.x).
extension-hyperlink installs @floating-ui/dom and linkifyjs. extension-hypermultimedia installs @floating-ui/dom. The other three install with no runtime dependencies. None of the five declares a Node or Bun engine floor.
extension-inline-code is the one package with an extra floor. Its backtick rules use RegExp lookbehind, so it needs an engine with RegExp lookbehind — Chrome 62+, Firefox 78+, Safari and iOS Safari 16.4+.
Two packages ship a stylesheet, imported as @docs.plus/extension-hyperlink/styles.css and @docs.plus/extension-hypermultimedia/styles.css. The other three ship no CSS. The extension-inline-code and extension-placeholder Quickstarts show the rule to add. extension-indent needs a rule only in the two cases that its Styling section lists. extension-placeholder renders nothing at all until you add its Quickstart rule.
None of the five imports React, Vue, or Next.js.
Use them from a plain page, Vite, React, Vue, Svelte, Next.js, Nuxt, or SvelteKit. Create the editor in the browser. Each Quickstart shows that call.
React Native has no DOM. Load the editor in a web view.
Three of these entries are required, not optional: two packages replace a StarterKit mark, and one replaces a Tiptap built-in.
- Hyperlink + StarterKit — required.
StarterKit.configure({ link: false }). StarterKit v3 bundles@tiptap/extension-link. The two marks collide on thesetLink/unsetLink/toggleLinkcommand names and on thea[href]parse rule. Yourextensionsarray order then decides each contest, with no warning. If the upstream mark wins, this package's scheme gate never runs on parsed or pasted HTML. - Inline code + StarterKit — required.
StarterKit.configure({ code: false }). Both marks render<code>and both bindMod-e. - Placeholder + the Tiptap built-in — required. Remove the built-in from the extensions array. Both register the name
placeholder, so both decorate the document. - Hyperlink + hypermultimedia.
Hyperlink.configure({ shouldAutoLink: (url) => !isMediaUrl(url) }), so a pasted media URL becomes a media node instead of a link.isMediaUrlmatches every provider whatever the kit configuration holds, so compose the veto from the per-provider validators when you disable providers. Each package also owns its own popover controller, so opening a popover in one never dismisses the popover of the other. - Indent + lists and tables.
@tiptap/extension-listand@tiptap/extension-tablebind Tab at the Tiptap defaultpriority: 100.extension-indentregisters at25, so it sees Tab last, and literal indent runs only where list and table both returnfalse.
The package READMEs are written for AI coding agents as well as people. Each Caveats section lists every setup mistake that fails with no error. Each Quickstart runs as written, and an Open in StackBlitz button runs it.
Point your agent at the README for the version you installed. jsDelivr serves it as plain Markdown:
https://cdn.jsdelivr.net/npm/@docs.plus/extension-<name>@<version>/README.md
The docs are also indexed on Context7 as the library /docs-plus/docs.plus. Agents that use the Context7 MCP server can look them up there.
The five packages use these words and no synonym. Two axes, never one word for both jobs:
- Popover — the positioning container: anchored, floating, light-dismiss. Owned by the shared
floating-popoverengine; shells are role-less by default (ARIA has no popover role — the surface carries its content's role). - Toolbar / form / menu — the content inside a surface, named by what it is and carrying the matching ARIA role. In hypermultimedia, the media toolbar is a persistent in-node action bar (
role="toolbar"). In hyperlink, the preview is a toolbar in a popover, and create/edit are forms (role="dialog") in popovers. - Composed names follow the industry shape (CKEditor "balloon toolbar", Fluent
MenuPopover):openToolbarPopoveropens a popover anchored to the media toolbar.
Four packages carry a Keyboard shortcuts table, and every Context cell in them names one of these surfaces. extension-placeholder binds no key, so it carries no such table.
| Surface | Package | What it names |
|---|---|---|
document |
hyperlink, hypermultimedia, indent, inline-code | a key bound on the editor document |
popover |
hyperlink | the popover root, whatever content it holds |
create-link form |
hyperlink | the create-link form content |
edit-link form |
hyperlink | the edit-link form content |
media toolbar |
hypermultimedia | the in-node action bar at the node's top-right corner |
media caption |
hypermultimedia | the editable <figcaption> on a media node |
replace-URL form |
hypermultimedia | the URL form the Replace URL action opens |
resize drag |
hypermultimedia | a pointer drag on a gripper handle |
RELEASE_POLICY.md — versioning doctrine, lockstep, release readiness, CHANGELOG style.
Per-package npm status and the publish runbook: .cursor/docs/extension-version-cutover.md.
Each package has its own CONTRIBUTING.md — see
hyperlink,
hypermultimedia (full README Gallery, 20 PNGs),
indent,
inline-code, and
placeholder. Hero or gallery PNGs: bun run docs:screenshots
in the package (cypress/docs/ → assets/). Hero GIFs for hyperlink and hypermultimedia: bun run docs:gif, which needs ffmpeg. Each examples/vanilla app must match its README Quickstart; bun scripts/check-quickstart-example.ts --write <extension-dir> regenerates it.
Monorepo development needs Node >=24.11.0 and Bun >=1.4.0, the floors the root package.json sets.
From the repo root:
bash scripts/build-extensions.sh
EXTENSION_DIST_READY=1 bash scripts/run-tests.sh --extensions
bash scripts/extension-preflight.shPackage list and gate metadata: scripts/publishable-extensions.ts (also imported by release-family.ts). CI sets EXTENSION_DIST_READY=1 after build-extensions so Cypress skips per-package pretest rebuilds.
To work on one extension, scope all three scripts with EXT_ONLY — space-separated directory names, the same variable CI passes per matrix job:
EXT_ONLY=extension-indent bash scripts/build-extensions.sh
EXT_ONLY=extension-indent EXTENSION_DIST_READY=1 bash scripts/run-tests.sh --extensions
EXT_ONLY=extension-indent bash scripts/extension-preflight.shbuild-extensions.sh builds floating-popover and floating-tooltip on every run, whatever EXT_ONLY holds, so hyperlink and hypermultimedia never miss the two packages they bundle. Separately, hypermultimedia's playground fixture imports @docs.plus/extension-hyperlink, so scope that pair together: EXT_ONLY="extension-hyperlink extension-hypermultimedia".
Per-package Discord embeds: RELEASE_POLICY.md.