Skip to content

Fix global attributes not syncing on resizable image updates#7568

Open
bdbch wants to merge 3 commits intomainfrom
claude/fix-resizable-attributes-d9M4b
Open

Fix global attributes not syncing on resizable image updates#7568
bdbch wants to merge 3 commits intomainfrom
claude/fix-resizable-attributes-d9M4b

Conversation

@bdbch
Copy link
Copy Markdown
Member

@bdbch bdbch commented Mar 6, 2026

Changes Overview

Fixed an issue where global attributes (added via extensions like custom ID attributes) were not being properly synced to the resizable image element when node attributes changed. The image extension now correctly renders and updates all global attributes on the <img> element within the resize container.

Implementation Approach

Modified the onUpdate callback in the resizable node view to:

  1. Use getRenderedAttributes() to compute all rendered attributes (including global attributes from extensions) for the updated node
  2. Sync attribute changes to the DOM by setting new attributes and removing attributes that are no longer present
  3. Track previous attributes to detect which ones should be removed
  4. Handle special cases like width/height (managed by resize logic) and src (requires direct property assignment)

This ensures that any attributes added by extensions are properly maintained when the node is updated, while preserving the existing resize functionality.

Testing Done

Added comprehensive test suite (packages/extension-image/__tests__/image.spec.ts) with 5 test cases covering:

  • Rendering global attributes on the resizable image element
  • Updating global attributes when node attributes change
  • Preserving global attributes when other attributes change
  • Updating src attribute on the resizable image
  • Removing attributes when set to null

All tests pass and verify that global attributes are correctly synced to the DOM element.

Verification Steps

  1. Run the test suite: npm test -- packages/extension-image
  2. Verify that all 5 tests in the "resizable image attribute updates" suite pass
  3. Test with a custom extension that adds global attributes to images and confirm they appear on the rendered <img> element
  4. Update image attributes via updateAttributes() and verify global attributes persist and update correctly

Additional Notes

The fix uses the existing getRenderedAttributes() utility from @tiptap/core to ensure consistency with how attributes are rendered elsewhere in the library. The implementation is careful to preserve the existing resize container behavior while adding proper attribute synchronization.

Checklist

  • I have created a changeset for this PR if necessary.
  • My changes do not break the library.
  • I have added tests where applicable.
  • I have followed the project guidelines.
  • I have fixed any lint issues.

Related Issues

Fixes #7542

Copilot AI review requested due to automatic review settings March 6, 2026 13:18
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 6, 2026

⚠️ No Changeset found

Latest commit: b40ad45

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@netlify
Copy link
Copy Markdown

netlify bot commented Mar 6, 2026

Deploy Preview for tiptap-embed ready!

Name Link
🔨 Latest commit b40ad45
🔍 Latest deploy log https://app.netlify.com/projects/tiptap-embed/deploys/69d0061ca0fa920008ef6acd
😎 Deploy Preview https://deploy-preview-7568--tiptap-embed.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a gap in the resizable image NodeView where global/rendered attributes (e.g. data-* from extensions like UniqueID) weren’t being kept in sync on node updates, by recomputing rendered attributes and applying them to the underlying <img>.

Changes:

  • Use getRenderedAttributes() during ResizableNodeView.onUpdate to include global attributes when syncing the <img> element.
  • Implement attribute diffing to add/update attributes and remove attributes that are no longer rendered.
  • Add a Vitest suite validating initial render, updates, preservation, and removals of attributes on resizable images.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
packages/extension-image/src/image.ts Updates resizable image NodeView onUpdate to sync rendered/global attributes onto the <img> element.
packages/extension-image/tests/image.spec.ts Adds unit tests covering resizable image attribute rendering and update/removal behavior.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 6, 2026

Open in StackBlitz

@tiptap/extension-character-count

npm i https://pkg.pr.new/@tiptap/extension-character-count@7568

@tiptap/extension-dropcursor

npm i https://pkg.pr.new/@tiptap/extension-dropcursor@7568

@tiptap/extension-focus

npm i https://pkg.pr.new/@tiptap/extension-focus@7568

@tiptap/extension-history

npm i https://pkg.pr.new/@tiptap/extension-history@7568

@tiptap/extension-gapcursor

npm i https://pkg.pr.new/@tiptap/extension-gapcursor@7568

@tiptap/extension-list-item

npm i https://pkg.pr.new/@tiptap/extension-list-item@7568

@tiptap/extension-list-keymap

npm i https://pkg.pr.new/@tiptap/extension-list-keymap@7568

@tiptap/extension-table-cell

npm i https://pkg.pr.new/@tiptap/extension-table-cell@7568

@tiptap/extension-table-header

npm i https://pkg.pr.new/@tiptap/extension-table-header@7568

@tiptap/extension-task-item

npm i https://pkg.pr.new/@tiptap/extension-task-item@7568

@tiptap/extension-table-row

npm i https://pkg.pr.new/@tiptap/extension-table-row@7568

@tiptap/extension-task-list

npm i https://pkg.pr.new/@tiptap/extension-task-list@7568

@tiptap/extension-placeholder

npm i https://pkg.pr.new/@tiptap/extension-placeholder@7568

@tiptap/core

npm i https://pkg.pr.new/@tiptap/core@7568

@tiptap/extension-audio

npm i https://pkg.pr.new/@tiptap/extension-audio@7568

@tiptap/extension-blockquote

npm i https://pkg.pr.new/@tiptap/extension-blockquote@7568

@tiptap/extension-bold

npm i https://pkg.pr.new/@tiptap/extension-bold@7568

@tiptap/extension-bubble-menu

npm i https://pkg.pr.new/@tiptap/extension-bubble-menu@7568

@tiptap/extension-bullet-list

npm i https://pkg.pr.new/@tiptap/extension-bullet-list@7568

@tiptap/extension-code

npm i https://pkg.pr.new/@tiptap/extension-code@7568

@tiptap/extension-code-block

npm i https://pkg.pr.new/@tiptap/extension-code-block@7568

@tiptap/extension-collaboration

npm i https://pkg.pr.new/@tiptap/extension-collaboration@7568

@tiptap/extension-code-block-lowlight

npm i https://pkg.pr.new/@tiptap/extension-code-block-lowlight@7568

@tiptap/extension-collaboration-caret

npm i https://pkg.pr.new/@tiptap/extension-collaboration-caret@7568

@tiptap/extension-color

npm i https://pkg.pr.new/@tiptap/extension-color@7568

@tiptap/extension-details

npm i https://pkg.pr.new/@tiptap/extension-details@7568

@tiptap/extension-document

npm i https://pkg.pr.new/@tiptap/extension-document@7568

@tiptap/extension-drag-handle-react

npm i https://pkg.pr.new/@tiptap/extension-drag-handle-react@7568

@tiptap/extension-drag-handle

npm i https://pkg.pr.new/@tiptap/extension-drag-handle@7568

@tiptap/extension-drag-handle-vue-2

npm i https://pkg.pr.new/@tiptap/extension-drag-handle-vue-2@7568

@tiptap/extension-drag-handle-vue-3

npm i https://pkg.pr.new/@tiptap/extension-drag-handle-vue-3@7568

@tiptap/extension-emoji

npm i https://pkg.pr.new/@tiptap/extension-emoji@7568

@tiptap/extension-file-handler

npm i https://pkg.pr.new/@tiptap/extension-file-handler@7568

@tiptap/extension-floating-menu

npm i https://pkg.pr.new/@tiptap/extension-floating-menu@7568

@tiptap/extension-font-family

npm i https://pkg.pr.new/@tiptap/extension-font-family@7568

@tiptap/extension-heading

npm i https://pkg.pr.new/@tiptap/extension-heading@7568

@tiptap/extension-highlight

npm i https://pkg.pr.new/@tiptap/extension-highlight@7568

@tiptap/extension-hard-break

npm i https://pkg.pr.new/@tiptap/extension-hard-break@7568

@tiptap/extension-horizontal-rule

npm i https://pkg.pr.new/@tiptap/extension-horizontal-rule@7568

@tiptap/extension-image

npm i https://pkg.pr.new/@tiptap/extension-image@7568

@tiptap/extension-invisible-characters

npm i https://pkg.pr.new/@tiptap/extension-invisible-characters@7568

@tiptap/extension-italic

npm i https://pkg.pr.new/@tiptap/extension-italic@7568

@tiptap/extension-link

npm i https://pkg.pr.new/@tiptap/extension-link@7568

@tiptap/extension-list

npm i https://pkg.pr.new/@tiptap/extension-list@7568

@tiptap/extension-mention

npm i https://pkg.pr.new/@tiptap/extension-mention@7568

@tiptap/extension-mathematics

npm i https://pkg.pr.new/@tiptap/extension-mathematics@7568

@tiptap/extension-node-range

npm i https://pkg.pr.new/@tiptap/extension-node-range@7568

@tiptap/extension-ordered-list

npm i https://pkg.pr.new/@tiptap/extension-ordered-list@7568

@tiptap/extension-paragraph

npm i https://pkg.pr.new/@tiptap/extension-paragraph@7568

@tiptap/extension-strike

npm i https://pkg.pr.new/@tiptap/extension-strike@7568

@tiptap/extension-subscript

npm i https://pkg.pr.new/@tiptap/extension-subscript@7568

@tiptap/extension-superscript

npm i https://pkg.pr.new/@tiptap/extension-superscript@7568

@tiptap/extension-text

npm i https://pkg.pr.new/@tiptap/extension-text@7568

@tiptap/extension-table

npm i https://pkg.pr.new/@tiptap/extension-table@7568

@tiptap/extension-table-of-contents

npm i https://pkg.pr.new/@tiptap/extension-table-of-contents@7568

@tiptap/extension-text-align

npm i https://pkg.pr.new/@tiptap/extension-text-align@7568

@tiptap/extension-text-style

npm i https://pkg.pr.new/@tiptap/extension-text-style@7568

@tiptap/extension-twitch

npm i https://pkg.pr.new/@tiptap/extension-twitch@7568

@tiptap/extension-typography

npm i https://pkg.pr.new/@tiptap/extension-typography@7568

@tiptap/extension-unique-id

npm i https://pkg.pr.new/@tiptap/extension-unique-id@7568

@tiptap/extension-underline

npm i https://pkg.pr.new/@tiptap/extension-underline@7568

@tiptap/extensions

npm i https://pkg.pr.new/@tiptap/extensions@7568

@tiptap/extension-youtube

npm i https://pkg.pr.new/@tiptap/extension-youtube@7568

@tiptap/html

npm i https://pkg.pr.new/@tiptap/html@7568

@tiptap/markdown

npm i https://pkg.pr.new/@tiptap/markdown@7568

@tiptap/pm

npm i https://pkg.pr.new/@tiptap/pm@7568

@tiptap/react

npm i https://pkg.pr.new/@tiptap/react@7568

@tiptap/starter-kit

npm i https://pkg.pr.new/@tiptap/starter-kit@7568

@tiptap/static-renderer

npm i https://pkg.pr.new/@tiptap/static-renderer@7568

@tiptap/vue-2

npm i https://pkg.pr.new/@tiptap/vue-2@7568

@tiptap/suggestion

npm i https://pkg.pr.new/@tiptap/suggestion@7568

@tiptap/vue-3

npm i https://pkg.pr.new/@tiptap/vue-3@7568

commit: 88c8409

@bdbch bdbch changed the base branch from develop to main March 14, 2026 15:04
claude added 2 commits April 3, 2026 20:12
When the image extension has resize enabled, it uses a custom NodeView.
The HTMLAttributes (including data-id from UniqueID extension) were only
applied once during node view creation. On subsequent node updates, the
onUpdate callback did not re-render attributes, causing extensions like
UniqueID to fail to add their attributes to resizable images.

Now the onUpdate callback re-computes rendered HTML attributes from the
updated node and applies them to the img element.

Fixes #7542

https://claude.ai/code/session_01T9FxnSEVbWimV5xdC9ftaw
- Replace `any` type on onUpdate with proper type derived from
  ResizableNodeViewOptions and getRenderedAttributes
- Track previous HTML attributes to detect and remove attributes
  that are no longer rendered (e.g., when a global attribute is
  set to null)
- Add unit tests covering global attribute rendering, updates,
  preservation across unrelated changes, src updates, and
  attribute removal on resizable images

https://claude.ai/code/session_01T9FxnSEVbWimV5xdC9ftaw
@bdbch bdbch force-pushed the claude/fix-resizable-attributes-d9M4b branch from 88c8409 to ce907db Compare April 3, 2026 18:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unique ID is not added to resizable images

3 participants