Skip to content

fix(hydration): pass namespace when patching dynamic props#15082

Merged
edison1105 merged 2 commits into
vuejs:mainfrom
rebeccarich:fix/hydration-svg-dynamic-props
Jul 16, 2026
Merged

fix(hydration): pass namespace when patching dynamic props#15082
edison1105 merged 2 commits into
vuejs:mainfrom
rebeccarich:fix/hydration-svg-dynamic-props

Conversation

@rebeccarich

@rebeccarich rebeccarich commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

close #15081
close #15050

During hydration, dynamic props are force-patched, but hydrateElement calls patchProp(el, key, null, prop [key], undefined, parentComponent) - the namespace argument is undefined. runtime-dom's patchProp derives isSVG from that namespace, so SVG/MathML elements are treated as HTML and read-only props (width, height, viewBox, …) are set as DOM properties, which throws:

[Vue warn]: Failed setting prop "viewBox" on <svg>: value 0 0 24 24 is invalid.
TypeError: Cannot set property viewBox of #<SVGSVGElement> which has only a getter

This forwards the element's namespace via the existing getContainerType(el) helper (already used for children hydration in the same file), so these props are patched via setAttribute, matching the normal client render path.

Regression range: 3.5.35 is unaffected (dynamic-prop force patch did not exist); 3.5.39 is broken.

Testing

Added a regression test in hydration.spec.ts that hydrates an <svg> with dynamic width/height/viewBox and asserts they are applied as attributes. The full runtime-core test suite passes.

Summary by CodeRabbit

Summary by CodeRabbit

  • Bug Fixes

    • Fixed hydration of namespaced elements (including SVG and nested foreignObject) so dynamically declared props correctly update the server-rendered DOM attributes (e.g., dimensions and viewBox).
    • Improved hydration patching by using the host element’s namespace to apply props with the correct attribute/property behavior.
  • Tests

    • Added hydration regression tests covering mismatch handling for the “force patch” path on SVG elements and foreignObject.

When force-patching dynamic props during hydration (introduced in vuejs#9083),
the element namespace is not forwarded to `patchProp`, so it defaults to
`undefined`. As a result `shouldSetAsProp` treats SVG (and MathML) elements
as HTML and patches read-only props such as `width`, `height` and `viewBox`
as DOM properties, which throws (e.g. "Cannot set property viewBox of
SVGSVGElement which has only a getter").

Forward the element's namespace via the existing `getContainerType` helper
so these props are patched as attributes, matching the normal render path.

close vuejs#15081

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Hydration now forwards the host element namespace when patching dynamic props. Regression tests cover dynamic width, height, and viewBox updates on hydrated SVG elements, including foreignObject.

Changes

SVG hydration

Layer / File(s) Summary
Namespace-aware hydration prop patching
packages/runtime-core/src/hydration.ts, packages/runtime-core/__tests__/hydration.spec.ts
hydrateElement derives SVG or MathML namespaces and passes them to patchProp; regression tests verify dynamic SVG and foreignObject attributes during hydration.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • vuejs/core#9083: Modifies hydration force-patching for dynamically declared vnode props.
  • vuejs/core#15086: Implements the same namespace-aware dynamic prop hydration behavior and related SVG tests.

Suggested reviewers: edison1105

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The code patches hydrated SVG/MathML props using the element namespace, matching the issue’s requirement to treat them as attributes.
Out of Scope Changes check ✅ Passed The added hydration regression tests are directly related to the namespace patching fix and no unrelated changes are evident.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: passing the element namespace when patching dynamic hydration props.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

Size Report

Bundles

File Size Gzip Brotli
runtime-dom.global.prod.js 107 kB (+84 B) 40.3 kB (+20 B) 36.3 kB (+23 B)
vue.global.prod.js 165 kB (+84 B) 60.4 kB (+16 B) 53.7 kB (-1 B)

Usages

Name Size Gzip Brotli
createApp (CAPI only) 49 kB 19 kB 17.4 kB
createApp 57.1 kB 22.1 kB 20.2 kB
createSSRApp 61.7 kB (+84 B) 24 kB (+27 B) 21.9 kB (+25 B)
defineCustomElement 63.3 kB 24 kB 21.9 kB
overall 71.9 kB 27.5 kB 25.1 kB

@pkg-pr-new

pkg-pr-new Bot commented Jul 15, 2026

Copy link
Copy Markdown

Open in StackBlitz

@vue/compiler-core

pnpm add https://pkg.pr.new/@vue/compiler-core@15082
npm i https://pkg.pr.new/@vue/compiler-core@15082
yarn add https://pkg.pr.new/@vue/compiler-core@15082.tgz

@vue/compiler-dom

pnpm add https://pkg.pr.new/@vue/compiler-dom@15082
npm i https://pkg.pr.new/@vue/compiler-dom@15082
yarn add https://pkg.pr.new/@vue/compiler-dom@15082.tgz

@vue/compiler-sfc

pnpm add https://pkg.pr.new/@vue/compiler-sfc@15082
npm i https://pkg.pr.new/@vue/compiler-sfc@15082
yarn add https://pkg.pr.new/@vue/compiler-sfc@15082.tgz

@vue/compiler-ssr

pnpm add https://pkg.pr.new/@vue/compiler-ssr@15082
npm i https://pkg.pr.new/@vue/compiler-ssr@15082
yarn add https://pkg.pr.new/@vue/compiler-ssr@15082.tgz

@vue/reactivity

pnpm add https://pkg.pr.new/@vue/reactivity@15082
npm i https://pkg.pr.new/@vue/reactivity@15082
yarn add https://pkg.pr.new/@vue/reactivity@15082.tgz

@vue/runtime-core

pnpm add https://pkg.pr.new/@vue/runtime-core@15082
npm i https://pkg.pr.new/@vue/runtime-core@15082
yarn add https://pkg.pr.new/@vue/runtime-core@15082.tgz

@vue/runtime-dom

pnpm add https://pkg.pr.new/@vue/runtime-dom@15082
npm i https://pkg.pr.new/@vue/runtime-dom@15082
yarn add https://pkg.pr.new/@vue/runtime-dom@15082.tgz

@vue/server-renderer

pnpm add https://pkg.pr.new/@vue/server-renderer@15082
npm i https://pkg.pr.new/@vue/server-renderer@15082
yarn add https://pkg.pr.new/@vue/server-renderer@15082.tgz

@vue/shared

pnpm add https://pkg.pr.new/@vue/shared@15082
npm i https://pkg.pr.new/@vue/shared@15082
yarn add https://pkg.pr.new/@vue/shared@15082.tgz

vue

pnpm add https://pkg.pr.new/vue@15082
npm i https://pkg.pr.new/vue@15082
yarn add https://pkg.pr.new/vue@15082.tgz

@vue/compat

pnpm add https://pkg.pr.new/@vue/compat@15082
npm i https://pkg.pr.new/@vue/compat@15082
yarn add https://pkg.pr.new/@vue/compat@15082.tgz

commit: 4484acb

@edison1105 edison1105 added ready to merge The PR is ready to be merged. 🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. scope:hydration labels Jul 15, 2026
@edison1105

Copy link
Copy Markdown
Member

/ecosystem-ci run

@vue-bot

vue-bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

📝 Ran ecosystem CI: Open

suite result latest scheduled
language-tools success success
primevue success success
quasar success success
pinia success success
radix-vue success success
nuxt success success
router success success
test-utils success success
vue-i18n success success
vue-macros success success
vitepress success success
vite-plugin-vue success success
vueuse success success
vuetify success success
vant success success
vue-simple-compiler success success

@edison1105 edison1105 merged commit e0d2723 into vuejs:main Jul 16, 2026
14 checks passed
kleintonno pushed a commit to raute1-org/LANoMAT that referenced this pull request Jul 16, 2026
Bump vue to 3.5.40 to pick up the upstream "hydration: pass namespace when
patching dynamic props" fix (vuejs/core#15082). Vue 3.5.39's new force-patch
of dynamic props during SSR hydration hardcoded a missing SVG namespace,
so patchProp mistook read-only SVG IDL properties (width/height/transform/
viewBox on rect/g/svg) for settable DOM props and threw on every hydrate,
flooding the console on /events/{slug}/seating and other SVG surfaces
(BracketConnector, SceneSeatmap). Pre-existing since M2; surfaced as a
console-cleanliness issue during the M13 design polish. No template changes
needed — the bindings were already correct.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. ready to merge The PR is ready to be merged. scope:hydration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SSR hydration warning: dynamic props on SVG elements are patched as properties instead of attributes

3 participants