ueberdosis/tiptap
 Watch   
 Star   
 Fork   
2 days ago
tiptap

v3.30.3

@tiptap/extension-text-style

Patch Changes

  • Unsetting one text style inside a blockquote no longer removes the other text styles in it.

@tiptap/extension-youtube

Patch Changes

  • YouTube live URLs (/live/<id>) now embed the video.

@tiptap/core

Patch Changes

  • Fix JSX runtime to properly render nested sibling elements by spreading children arrays into DOMOutputSpec

@tiptap/react

Patch Changes

  • Fix ReactNodeViewRenderer crash when contentComponent is not available

@tiptap/ai-toolkit

Minor Changes

  • Add the AiInsertReveal extension (@tiptap/ai-toolkit/streaming-reveal) to fade in text as the AI streams it into a collaborative document.
8 days ago
tiptap

v3.30.2

@tiptap/core

Patch Changes

  • Keep mixed JSX children as separate siblings in DOM output.
  • Fixed a bug where editor.chain and editor.can can not be accessed on editor initialization

@tiptap/extension-image

Patch Changes

  • Fix resizable images staying hidden when the image is cached or fails to load.
13 days ago
tiptap

v3.30.1

@tiptap/extension-table

Patch Changes

  • Fixed table markdown pipe escaping so the extension loads on older Safari and iOS versions (WebKit before Safari 16.4).

@tiptap/core

Patch Changes

  • Added new ProseMirror helpers that check whether a value is a specific ProseMirror type.
15 days ago
tiptap

v3.30.0

v3.30.0

@tiptap/vue-2

Minor Changes

  • ceb0dac: New Decorations API

    Finally the decorations API is here! Even though Decorations itself are nothing new in ProseMirror, the new API makes it much easier to use them in Tiptap without leaving your extensions.

    Decorations change how the document looks without changing the document itself. Highlighting search results, marking spelling mistakes, showing collaborator cursors, putting a drag handle next to every block.

    Until now you had to write a ProseMirror plugin by hand for this, keep the decoration set in plugin state, and map it forward on every transaction. Extensions can now declare decorations directly with a new addDecorations() hook.

    addDecorations() {
      return {
        create: ({ state }) =>
          // findMatches can be any function that returns an array of { from, to } ranges
          findMatches(state.doc).map(match =>
            Decoration.Inline(match.from, match.to, { class: 'highlight' }),
          ),
      }
    }

    There are three kinds. Decoration.Inline() styles a range of text. Decoration.Node() puts attributes on a block's DOM element. Decoration.Widget() renders your own element at a single position.

    Every extension that declares decorations is collected into one plugin, so several extensions can decorate the same document without fighting over it.

    Doing less work on every keystroke

    By default decorations are rebuilt whenever the document changes. That is fine for small documents and wasteful for large ones, so there are two ways to narrow it down.

    shouldUpdate() skips transactions you do not care about. If your decorations only depend on headings, ignore everything else.

    update: 'changedRanges' together with createInRange() only rescans the blocks that actually changed. On a long document this is the difference between scanning the whole thing on every keystroke and scanning one paragraph.

    For decorations driven by data outside the editor, like comments loaded from a server, use update: 'manual' and refresh them yourself with editor.commands.updateDecorations().

    React and Vue components as widgets

    ReactWidgetRenderer and VueWidgetRenderer render a real component into a widget decoration, inside your existing app context. Providers, context and stores work as usual.

    Widgets take a key. Reuse the same key and the component instance stays mounted while the document changes around it, so local state such as an open menu, a counter or a half-typed input survives editing. Use a stable id from your own data, not a position or a list index, otherwise the component remounts and loses that state.

    Widgets also accept the ProseMirror options side, relaxedSide, stopEvent and ignoreSelection.

    Documentation

Patch Changes

  • ceb0dac: Fix FloatingMenu not registering when the editor prop is provided synchronously, which prevented the menu from appearing

@tiptap/extension-list

Minor Changes

  • ceb0dac: ListKeymap now registers a Tab shortcut that sinks a top-level textblock into the previous list's last item. Pressing Tab at the start of a paragraph right after a bullet/ordered/task list moves the paragraph inside the last list item. The handler does nothing when the cursor is already inside a list item (sinkListItem keeps working), when there is no list before the paragraph, when the caret is mid-textblock, or when the selection is not a text selection (for example a gap cursor).

    @tiptap/core also exposes a new getPreviousBlockSibling($pos) helper that returns the block-level sibling before the cursor's textblock, or null at the first child of the block parent.

Patch Changes

  • ceb0dac: Parse block math that follows an ordered list item without a blank line, both after the list and indented inside the item, instead of pulling it into the item's text.
  • ceb0dac: TaskItem: the checkbox label now also fills the wrapping label element, so accessibility audits no longer flag it as empty.

@tiptap/core

Minor Changes

  • ceb0dac: ListKeymap now registers a Tab shortcut that sinks a top-level textblock into the previous list's last item. Pressing Tab at the start of a paragraph right after a bullet/ordered/task list moves the paragraph inside the last list item. The handler does nothing when the cursor is already inside a list item (sinkListItem keeps working), when there is no list before the paragraph, when the caret is mid-textblock, or when the selection is not a text selection (for example a gap cursor).

    @tiptap/core also exposes a new getPreviousBlockSibling($pos) helper that returns the block-level sibling before the cursor's textblock, or null at the first child of the block parent.

  • ceb0dac: New Decorations API

    Finally the decorations API is here! Even though Decorations itself are nothing new in ProseMirror, the new API makes it much easier to use them in Tiptap without leaving your extensions.

    Decorations change how the document looks without changing the document itself. Highlighting search results, marking spelling mistakes, showing collaborator cursors, putting a drag handle next to every block.

    Until now you had to write a ProseMirror plugin by hand for this, keep the decoration set in plugin state, and map it forward on every transaction. Extensions can now declare decorations directly with a new addDecorations() hook.

    addDecorations() {
      return {
        create: ({ state }) =>
          // findMatches can be any function that returns an array of { from, to } ranges
          findMatches(state.doc).map(match =>
            Decoration.Inline(match.from, match.to, { class: 'highlight' }),
          ),
      }
    }

    There are three kinds. Decoration.Inline() styles a range of text. Decoration.Node() puts attributes on a block's DOM element. Decoration.Widget() renders your own element at a single position.

    Every extension that declares decorations is collected into one plugin, so several extensions can decorate the same document without fighting over it.

    Doing less work on every keystroke

    By default decorations are rebuilt whenever the document changes. That is fine for small documents and wasteful for large ones, so there are two ways to narrow it down.

    shouldUpdate() skips transactions you do not care about. If your decorations only depend on headings, ignore everything else.

    update: 'changedRanges' together with createInRange() only rescans the blocks that actually changed. On a long document this is the difference between scanning the whole thing on every keystroke and scanning one paragraph.

    For decorations driven by data outside the editor, like comments loaded from a server, use update: 'manual' and refresh them yourself with editor.commands.updateDecorations().

    React and Vue components as widgets

    ReactWidgetRenderer and VueWidgetRenderer render a real component into a widget decoration, inside your existing app context. Providers, context and stores work as usual.

    Widgets take a key. Reuse the same key and the component instance stays mounted while the document changes around it, so local state such as an open menu, a counter or a half-typed input survives editing. Use a stable id from your own data, not a position or a list index, otherwise the component remounts and loses that state.

    Widgets also accept the ProseMirror options side, relaxedSide, stopEvent and ignoreSelection.

    Documentation

Patch Changes

  • ceb0dac: Fixed insertContent, insertContentAt and setContent failing when prosemirror-model is loaded more than once.

@tiptap/starter-kit

Patch Changes

  • ceb0dac: StarterKit now pins its bundled @tiptap/* dependencies to the exact version it was released with, so installing a specific StarterKit version gives you that version's extension set instead of the newest one.

@tiptap/react

Minor Changes

  • ceb0dac: New Decorations API

    Finally the decorations API is here! Even though Decorations itself are nothing new in ProseMirror, the new API makes it much easier to use them in Tiptap without leaving your extensions.

    Decorations change how the document looks without changing the document itself. Highlighting search results, marking spelling mistakes, showing collaborator cursors, putting a drag handle next to every block.

    Until now you had to write a ProseMirror plugin by hand for this, keep the decoration set in plugin state, and map it forward on every transaction. Extensions can now declare decorations directly with a new addDecorations() hook.

    addDecorations() {
      return {
        create: ({ state }) =>
          // findMatches can be any function that returns an array of { from, to } ranges
          findMatches(state.doc).map(match =>
            Decoration.Inline(match.from, match.to, { class: 'highlight' }),
          ),
      }
    }

    There are three kinds. Decoration.Inline() styles a range of text. Decoration.Node() puts attributes on a block's DOM element. Decoration.Widget() renders your own element at a single position.

    Every extension that declares decorations is collected into one plugin, so several extensions can decorate the same document without fighting over it.

    Doing less work on every keystroke

    By default decorations are rebuilt whenever the document changes. That is fine for small documents and wasteful for large ones, so there are two ways to narrow it down.

    shouldUpdate() skips transactions you do not care about. If your decorations only depend on headings, ignore everything else.

    update: 'changedRanges' together with createInRange() only rescans the blocks that actually changed. On a long document this is the difference between scanning the whole thing on every keystroke and scanning one paragraph.

    For decorations driven by data outside the editor, like comments loaded from a server, use update: 'manual' and refresh them yourself with editor.commands.updateDecorations().

    React and Vue components as widgets

    ReactWidgetRenderer and VueWidgetRenderer render a real component into a widget decoration, inside your existing app context. Providers, context and stores work as usual.

    Widgets take a key. Reuse the same key and the component instance stays mounted while the document changes around it, so local state such as an open menu, a counter or a half-typed input survives editing. Use a stable id from your own data, not a position or a list index, otherwise the component remounts and loses that state.

    Widgets also accept the ProseMirror options side, relaxedSide, stopEvent and ignoreSelection.

    Documentation

Patch Changes

  • ceb0dac: React node views no longer show the selected state when the selection covers a position the node view has moved away from.

@tiptap/markdown

Patch Changes

  • ceb0dac: Markdown with inline HTML such as an unclosed <b> tag no longer parses into an invalid document. The tag is dropped and its text is kept.

@tiptap/static-renderer

Patch Changes

  • ceb0dac: Fixed table cell and header spans in the React static renderer.

@tiptap/pm

Patch Changes

  • ceb0dac: Fix the ./schema-list export map pointing types at dist/schema/, which is not emitted. Tools that read the types condition directly could not resolve @tiptap/pm/schema-list.

@tiptap/extension-table

Patch Changes

  • ceb0dac: Deleting the last row or column of a table no longer moves the cursor outside the table when there is content below it.

@tiptap/extension-drag-handle-react

Patch Changes

  • ceb0dac: Fixed the React DragHandle breaking drag-and-drop when onNodeChange is an inline callback, by no longer re-registering its plugin when a callback's identity changes.

@tiptap/extension-mathematics

Patch Changes

  • ceb0dac: Allow KaTeX 0.18 to be installed with the math extension

@tiptap/extension-blockquote

Patch Changes

  • ceb0dac: Fixed Backspace freezing after merging a paragraph into a blockquote.

@tiptap/vue-3

Minor Changes

  • ceb0dac: New Decorations API

    Finally the decorations API is here! Even though Decorations itself are nothing new in ProseMirror, the new API makes it much easier to use them in Tiptap without leaving your extensions.

    Decorations change how the document looks without changing the document itself. Highlighting search results, marking spelling mistakes, showing collaborator cursors, putting a drag handle next to every block.

    Until now you had to write a ProseMirror plugin by hand for this, keep the decoration set in plugin state, and map it forward on every transaction. Extensions can now declare decorations directly with a new addDecorations() hook.

    addDecorations() {
      return {
        create: ({ state }) =>
          // findMatches can be any function that returns an array of { from, to } ranges
          findMatches(state.doc).map(match =>
            Decoration.Inline(match.from, match.to, { class: 'highlight' }),
          ),
      }
    }

    There are three kinds. Decoration.Inline() styles a range of text. Decoration.Node() puts attributes on a block's DOM element. Decoration.Widget() renders your own element at a single position.

    Every extension that declares decorations is collected into one plugin, so several extensions can decorate the same document without fighting over it.

    Doing less work on every keystroke

    By default decorations are rebuilt whenever the document changes. That is fine for small documents and wasteful for large ones, so there are two ways to narrow it down.

    shouldUpdate() skips transactions you do not care about. If your decorations only depend on headings, ignore everything else.

    update: 'changedRanges' together with createInRange() only rescans the blocks that actually changed. On a long document this is the difference between scanning the whole thing on every keystroke and scanning one paragraph.

    For decorations driven by data outside the editor, like comments loaded from a server, use update: 'manual' and refresh them yourself with editor.commands.updateDecorations().

    React and Vue components as widgets

    ReactWidgetRenderer and VueWidgetRenderer render a real component into a widget decoration, inside your existing app context. Providers, context and stores work as usual.

    Widgets take a key. Reuse the same key and the component instance stays mounted while the document changes around it, so local state such as an open menu, a counter or a half-typed input survives editing. Use a stable id from your own data, not a position or a list index, otherwise the component remounts and loses that state.

    Widgets also accept the ProseMirror options side, relaxedSide, stopEvent and ignoreSelection.

    Documentation

29 days ago
tiptap

v3.29.2

@tiptap/react

Patch Changes

  • Fixed the caret jumping back to the previous block when pressing Enter inside a React node view.

@tiptap/extension-find-and-replace

Patch Changes

  • Ensure only the active find-and-replace result keeps the current-result highlight while navigating matches.
2026-07-27 17:27:38
tiptap

v3.29.1

@tiptap/react

Patch Changes

  • 6d901e7: Fix caret placement after splitting a block rendered with a React NodeView.
2026-07-24 20:46:53
tiptap

v3.29.0

@tiptap/extension-ruby-text

Minor Changes

  • Add official RubyText extension for HTML ruby text annotations with non-editable annotations and mark-based document storage. The click-to-edit annotation editor can be replaced with a custom element via the renderAnnotationEditor option.

@tiptap/core

Patch Changes

  • Fix a TypeScript build error in isAndroid() where comparing navigator.platform against the literal 'Android' with === could fail to compile under some lib.dom.d.ts typings ("types have no overlap"). Switched to the same .includes() pattern already used by isiOS(), which is not affected by this TypeScript narrowing issue. No runtime behavior change.
  • Fixed a bug where deleting an AllSelection (for example right after Ctrl/Cmd+A) left a lingering "phantom" selection highlight over the emptied document instead of a text cursor. deleteSelection now collapses the selection to a cursor.
  • Fix input rules crashing when the matched text spans an inline atom node like a mention.
  • Node view getPos() now returns undefined instead of throwing when the position cannot be resolved yet, for example when React 19 renders a node view component while the editor view is still updating.
  • Fixed onContentError throwing when calling editor.commands from inside the handler on initial load with invalid content. The editor now has a usable state (seeded from the stripped fallback document) before onContentError fires.
  • Fix editor.$pos() returning the wrong node inside container nodes, for example the list item instead of the list.
  • Add insertDefaultBlock to insert the default textblock allowed at a position. It accepts an optional position, attributes, content, and selection-update option.
  • Updated dependencies [e9942fc]
    • @tiptap/pm@3.29.0

@tiptap/extension-find-and-replace

Minor Changes

  • Added a new @tiptap/extension-find-and-replace extension. It searches the document for a term, highlights all matches with decorations, and replaces the current or all matches. Supports case-sensitive, whole-word, and RE2-compatible regex search, plus commands to jump between results. Regex search avoids catastrophic backtracking but does not support lookarounds or backreferences.

@tiptap/pm

Patch Changes

  • Bump prosemirror-model to ^1.25.11, fixing pasting content copied from the editor inserting extra empty paragraphs (a regression introduced in prosemirror-view 1.42.0).

@tiptap/extension-hard-break

Patch Changes

  • Fixed a bug where inserted hard breaks would not scroll the view on insertion via commands.

@tiptap/extension-code-block

Patch Changes

  • Fixed a bug where pressing ArrowUp in a code block that is the first node in the document did nothing, leaving no way to insert content above it. A new default block is now inserted above the code block, mirroring the existing ArrowDown behavior. The behavior can be disabled via the new exitOnArrowUp option.

@tiptap/extension-table

Patch Changes

  • Fix inserting a table with an empty cell or header (e.g. via insertContent/insertContentAt) throwing RangeError: Invalid content for node tableCell/tableHeader: <>. Empty <td>/<th> elements are now backfilled with the cell's default block content, matching the behavior you already get from setContent.
  • Keep line breaks inside table cells when serializing to markdown. Hard breaks and paragraph breaks in a cell are now written as <br> instead of being collapsed into a space, so they survive a parse/serialize round trip.

@tiptap/markdown

Patch Changes

  • Fixed blank lines being dropped after block elements (headings, tables, etc.) when parsing markdown. Blank lines were being absorbed into the block token instead of being preserved, causing content to lose a blank line on each parse/serialize cycle.

@tiptap/react

Patch Changes

  • Fixed useEditorState not re-rendering components when editor.setEditable() changes the editor's editable state, since that call only emits an update event and never a transaction.

@tiptap/vue-3

Patch Changes

  • Fix <node-view-content as="tbody"> (and similar restricted-content elements) rendering with an extra wrapper <div> nested inside them, which broke tables in Vue node views. Note: keep <node-view-content> mounted (use v-show, not v-if) — conditionally remounting it can leave ProseMirror attached to the old element.

@tiptap/extension-image

Patch Changes

  • Fix resizable images not synchronizing rendered attributes after updates

@tiptap/static-renderer

Patch Changes

  • Fix Markdown table serialization for merged cells by preserving the correct column layout for rowspan and colspan.

@tiptap/extension-link

Minor Changes

  • Typing or pasting Markdown link syntax like [Tiptap](https://tiptap.dev) or [Tiptap](https://tiptap.dev "Rich text editor") can now automatically be converted into a link. The behavior is opt-in, enable it with the new markdownLinks option.
2026-07-16 06:45:31
tiptap

v3.28.0

@tiptap/extension-details

Patch Changes

  • 8614730: Fix the cursor moving to the details summary after typing in content at the start of a document.
  • @tiptap/core@3.28.0
    • @tiptap/extension-text-style@3.28.0
    • @tiptap/pm@3.28.0

@tiptap/extension-list

Patch Changes

  • 8614730: Fix markdown parsing a line like (216) 555-1234 as an ordered list. A number followed by ) mid-line is no longer treated as a list marker.
  • @tiptap/core@3.28.0
    • @tiptap/pm@3.28.0

@tiptap/react

Patch Changes

  • 8614730: Batch React node view portal store notifications that happen in the same microtask to avoid nested update depth warnings when many node views mount together.
  • 8614730: Bind onMount and onUnmount event handlers when initializing an Editor with useEditor hook.
  • @tiptap/core@3.28.0
    • @tiptap/pm@3.28.0

@tiptap/extension-collaboration-caret

Patch Changes

  • 8614730: Bump @tiptap/y-tiptap version to ensure users use latest version
  • @tiptap/core@3.28.0
    • @tiptap/pm@3.28.0

@tiptap/extension-collaboration

Patch Changes

  • 8614730: Bump @tiptap/y-tiptap version to ensure users use latest version
  • @tiptap/core@3.28.0
    • @tiptap/pm@3.28.0

@tiptap/extension-drag-handle

Patch Changes

  • 8614730: Bump @tiptap/y-tiptap version to ensure users use latest version
  • Updated dependencies [8614730]
    • @tiptap/extension-collaboration@3.28.0
    • @tiptap/core@3.28.0
    • @tiptap/extension-node-range@3.28.0
    • @tiptap/pm@3.28.0

@tiptap/extension-youtube

Minor Changes

  • 8614730: Allow string width and height values like '100%' or '20rem' in the YouTube extension. Non-numeric values in parsed HTML are now preserved instead of being converted to numbers.
2026-07-13 22:40:28
tiptap

v3.27.4

@tiptap/extensions

Patch Changes

  • 0fde1e8: Fixed the Selection extension leaving the native browser selection visible on blur, where it overlapped the selection decoration. The native selection is now cleared on blur and restored on focus.
  • @tiptap/core@3.27.4
    • @tiptap/pm@3.27.4

@tiptap/extension-blockquote

Patch Changes

  • 0fde1e8: Fix a crash when pressing backspace at the very start of the document with a leading image. The blockquote backspace handler dereferenced an undefined parent at the top (doc) level, throwing TypeError: Cannot read properties of undefined (reading 'type'). It now bails out so backspace is a no-op at the document start.
  • 0fde1e8: Add @tiptap/pm as a peer dependency so bundlers resolve ProseMirror packages from the app instead of duplicating prosemirror-model inside @tiptap/extension-blockquote.
  • @tiptap/core@3.27.4
    • @tiptap/pm@3.27.4

@tiptap/extension-table

Patch Changes

  • 0fde1e8: Fix <col width> in a table's <colgroup> being ignored when parsing HTML. The width of the first column was always dropped because the cell index 0 failed a truthiness check, and header cells (<th>) never read the colgroup at all. Both table cells and table headers now fall back to the matching <col> element's width attribute when they have no colwidth attribute of their own.
  • 0fde1e8: Fix pipe characters inside backtick inline code spans being incorrectly treated as table column delimiters in both leading-pipe and pipeless (no leading |) GFM tables. Cells containing expressions like `||` or `a || b` now parse correctly instead of splitting into extra columns and losing their code formatting.
  • @tiptap/core@3.27.4
    • @tiptap/pm@3.27.4

@tiptap/extension-list

Patch Changes

  • 0fde1e8: Fix a markdown parsing bug where a plain bullet (- item) nested under a task-list parent (- [ ]) was silently dropped from the parsed document. The task-list tokenizer's nested parser stopped at the first non-checkbox line and discarded everything after it; that remainder is now lexed and kept as sibling blocks (a bullet list or paragraph inside the parent task item), matching how mixed lists already behave at the top level.
  • @tiptap/core@3.27.4
    • @tiptap/pm@3.27.4

@tiptap/react

Patch Changes

  • 0fde1e8: Add a use client directive so @tiptap/react can be imported from React Server Components without crashing. Core symbols re-exported through @tiptap/react now cross the client boundary too, so import them from @tiptap/core directly in server code.
2026-07-07 16:30:14
tiptap

v3.27.3

@tiptap/core

Patch Changes

  • 94de762: Fix deleteSelection to delete content across all selection ranges instead of only the first range. This restores multi-cell table selections and other custom selections with multiple ranges.
  • @tiptap/pm@3.27.3

@tiptap/extension-list

Patch Changes

  • 94de762: Fix markdown parsing bugs where block elements right after an ordered list item (with no blank line in between) were wrongly treated as lazy continuation of the list item, instead of terminating the list the way other markdown parsers do:

    • Thematic breaks (---, ***, ___, * * *) were swallowed into the list item as literal paragraph text — along with every line after them. They now terminate the list and become a horizontal rule.
    • Fenced code blocks (``` and ~~~) were nested inside the list item. They now terminate the list and become a top-level code block.
    • Unindented bullet markers (- item) were nested inside the ordered list item. They now terminate the ordered list and start a new top-level bullet list. Indented bullets still nest inside the item as before.

    An indented ***/___ inside item content is now also parsed as a horizontal rule inside the item instead of literal text. A --- line directly below item paragraph text keeps its current behavior because it is a setext heading underline per CommonMark, not a thematic break.

  • 94de762: Fix indented ordered list items (e.g. one leading space before the marker, as happens when a top-level ordered list is itself nested inside another list) losing inline formatting during markdown parsing. The custom ordered-list markdown tokenizer built its nested structure with a hardcoded base indentation of 0, so an item whose actual indentation was non-zero never matched, causing the tokenizer to silently produce zero items and bail out — falling back to a path that left the item's content as literal, unparsed text instead of running it through inline tokenization (bold, italic, etc. were lost). The base indentation is now taken from the first collected item instead of being hardcoded.

  • Updated dependencies [94de762]

    • @tiptap/core@3.27.3
    • @tiptap/pm@3.27.3

@tiptap/extensions

Patch Changes

  • 94de762: Fixed placeholder flickering and disappearance on large documents. Replaced the viewport-based decoration scan with an incremental StateField<DecorationSet> that only re-computes decorations for top-level nodes touched by each transaction. This eliminates the dependency on DOM measurement (posAtCoords), requestAnimationFrame scheduling, and scroll listeners that caused flickering under collaboration, occlusion, and rapid edits.