-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Description
Affected Packages
extension-text-style
Version(s)
3.20.3
Bug Description
- Select any piece of text in the editor and apply color to it (make sure the text at the end of the paragraph is colored).
- Insert the cursor before the last character in the paragraph.
- Insert a character using the input method.
- The cursor ends up at the end of the paragraph.
2026-03-17.21.54.39.mov
Move the cursor to the end of the paragraph.
Browser Used
Chrome
Code Example URL
https://tiptap.dev/docs/ui-components/components/color-text-button
Expected Behavior
The cursor is expected to remain before the last character, not after it.
Additional Context (Optional)
In fact, this issue does not occur in Firefox or Safari. Even on Tiptap’s official website, the problem exists on some pages but not others.
Affected pages (with the issue):
- https://tiptap.dev/docs/ui-components/components/color-text-button
- https://templates.tiptap.dev/Fjt9rjmh8h
Unaffected pages (no issue):
- https://tiptap.dev/docs/editor/extensions/functionality/color
- The Notion-like editor at https://tiptap.dev/
Based on my debugging, the code execution flow when inputting characters via an input method is as follows:
- In
prosemirror-view/domchange.ts(lines 108–122):parseBetweenandfindDiffcompare the current ProseMirror state with the DOM-parsed result. - In
prosemirror-model/diff.ts(line 37):findDiffEndcallssameMarkupand returns early when marks do not match. - Since
injectExtensionAttributesToParseRulein@tiptap/coreskipsnull/undefinedvalues but retains empty strings (""), it causes an inconsistency between the ProseMirror state (null) and the DOM parse result (""). - In
prosemirror-view/domchange.ts(lines 233–237): WhenfindDiffreturns{start:1, endA:3, endB:3}(where3represents the positional coordinate of the cursor at the end of the line), the conditionsel.head == tr.mapping.map(chTo) - 1evaluates totrue. This preventsparse.selfrom being applied, leaving the cursor stuck at the incorrect position.
Based on point 3 above, I believe the logic of injectExtensionAttributesToParseRule is correct. Instead, I suggest modifying the default values of the parseHTML method in the following files under the packages/extension-text-style directory to either null or undefined:
src/background-color/background-color.tssrc/color/color.tssrc/font-family/font-family.tssrc/font-size/font-size.tssrc/line-height/line-height.ts
Additionally, this issue also occurs if the version of prosemirror-model in demos/package.json is upgraded to v1.25.2.
ProseMirror introduced a change in version 1.25.2 (commit e73b74c, July 2, 2025):
- v1.24.1:
dom.setAttribute("style", "color: #F98181")→getAttribute('style')returns"color: #F98181"→parseHTMLreceives the original hex value → consistent with the ProseMirror state. - v1.25.2:
dom.style.cssText = "color: #F98181"→ Chrome normalizes the value →getAttribute('style')returns"color: rgb(249, 129, 129);"→parseHTMLreceives the RGB value → inconsistent with the hex value in the ProseMirror state.
This change was implemented to bypass CSP (Content Security Policy) restrictions (Issue #1522), but it introduced an unintended side effect of color value normalization. I hope this issue can also be addressed and fixed.
Dependency Updates
- Yes, I've updated all my dependencies.