Repository navigation
fix: keep the namespace prefix in attributes() - #2941
Merged
cexbrayat merged 1 commit intoSep 18, 2026
Merged
Conversation
`attributes()` indexed the returned map by `Attr.localName`, which strips
the namespace prefix. Vue sets `xlink:*` attributes on SVG elements with
`setAttributeNS`, so `<use xlink:href="#icon" />` was reported as
`{ href: '#icon' }`, `attributes('xlink:href')` returned `undefined`, and
an element carrying both `xlink:href` and `href` lost one of them because
the two collided on the same key.
Index by `Attr.name` instead, which is the qualified name and matches what
`html()` renders. HTML attribute names are already lowercased by the
parser, so unprefixed attributes are unaffected.
✅ Deploy Preview for vue-test-utils-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Contributor
|
Reviewed the change and verified the DOM semantics it relies on (jsdom, same as the test env): for // main (attribute.localName) — xlink value silently lost to the collision
{ href: '#fallback', viewBox: '0 0 2 2' }
// PR (attribute.name) — both preserved
{ 'xlink:href': '#icon', href: '#fallback', viewBox: '0 0 2 2' }Two things worth noting in favor:
No other concerns: the regression test locks both the prefixed key and the coexistence case. One process note — the Node From my side this is good to merge once CI has run. |
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
attributes()indexed its result by the attribute's local name, so a namespaced attribute lost its prefix.xlink:*attributes on SVG elements were reported under the wrong key, and an element carrying bothxlink:hrefandhrefsilently lost one of the two.Root cause
src/baseWrapper.tsline 286 built the map withattributeMap[attribute.localName] = attribute.value.Attr.localNameis the name with the namespace prefix removed, soxlink:hrefis stored ashref. Vue setsxlink:*attributes on SVG elements throughsetAttributeNS(patchAttrin@vue/runtime-dom), which is the ordinary path for SVG sprite icons, so those attributes always arrive namespaced.Mounting
<svg><use xlink:href="#icon" href="#fallback" /></svg>onmaingives:Both attributes collide on the key
hrefand the last one wins, soattributes()andhtml()disagree about what the element carries.The same element shows the inconsistency from the other side:
xmlns:xlinkis written with plainsetAttributeand therefore has no namespace, so its prefix survives, whilexlink:hrefloses its own.Fix
Index by
Attr.name, the qualified name, which is exactly whathtml()renders.HTML attribute names are lowercased by the parser, so
nameandlocalNameare the same string for every attribute without a prefix, and unprefixed attributes are untouched. On an element that carries onlyxlink:href,attributes('href')no longer resolves to it: it is now reported underxlink:href.Validation
The regression test added to
tests/attributes.spec.tsfails onmainwithAssertionError: expected { href: '#fallback' } to deeply equal { 'xlink:href': '#icon', ... }and passes with the fix.vitest run --maxWorkers=3: 54 files, 505 passed, 1 todo, 0 failedrollup -c rollup.config.ts --bundleConfigAsCjsthenvitest run --mode test-build tests/attributes.spec.ts: 6 passed, confirming the built bundle behaves the samepnpm run lint: exit 0, andoxlint src/baseWrapper.ts tests/attributes.spec.tsreports nothingpnpm run format-check: all 239 files correctly formattedpnpm run tsd: exit 0pnpm run vue-tsc: exit 0