core icon indicating copy to clipboard operation
core copied to clipboard

Unexpected behaviour when `a` tag is given a `username` or `password` attribute

Open Ross-Alexandra opened this issue 1 year ago • 1 comments

Vue version

3.4.21

Link to minimal reproduction

https://play.vuejs.org/#eNp9kctOwzAQRX8leE0T8VhFoRJUXYDEQ8DSEnLTaeLW8Rh73FRU/XfGqVq6QN2N771jnxlvxb1z+TqCKEUVaq8dZQEourG0VbEXuOQDQeeMIuBTllUqaz0s7qRoiVwoi6Lv+7xBbAzkNXZSZDGAt6oDziwQZ8qz5lQIPfo5azP1w0LADkZILfiRIvJ6Fik1fMeNFOOJ0fUqe4aLqlADzgmCuBQUarQL3eTLgJbxtwlMCn7daQP+1ZFGG6Qos8FJnjIG+6dBIx/h8qDXLdSrf/RlYI6SizcPPM4apDh6pHwDtLenHy+w4fpodjiPhtNnzHcIaGJi3Mceop0z9kluoH3sHHrStvkM0w2BDYehEmhK7oa8FPyHkzOj/+He5LdDn7Q73uLXGny6kxfIRn59JXa/+CuwQQ==

Steps to reproduce

  1. Inspect the a tag in the DOM

What is expected?

The username and password attributes fall-through to the underlying a element in the DOM like in vanilla-HTML.

Here's an example fiddle showcasing what I was expected: https://codepen.io/Ross-Alexandra/pen/VwNagGR. If you inspect the a here, you'll see the username, password, and some-other-attribute attributes directly in the DOM.

What is actually happening?

The username & password attributes are being consumed, and prepended to the href as the authentication-part of the URL (ex: <a href="https://foobar:[email protected]"> is being rendered instead of <a href="https://www.google.com" username="foobar" password="baz">).

System Info

No response

Any additional comments?

I ran into this during a migration from Vue 2.7 to Vue 3.1. At some point when our codebase was still on Vue 2.x, we made a refactor which caused one of our components to no longer accept a username prop. This refactor wasn't properly completed however, as some of the references to that component were still passed a username. The root of that component is an a tag, so the username prop being passed to the component fell through to an attribute on the underlying a tag. This bug was then encountered, as that username attribute was prepended onto the href.

If this is working as intended, I was unable to find any documentation pointing this out.

Ross-Alexandra avatar Mar 11 '24 20:03 Ross-Alexandra

In Vue 3, the default way to add an element property/attribute is through the DOM property - if it exists.

i.e.:

const el = document.createElement('div')
// setting an id happens through the DOM property, because 'id in el' => true
// so Vue does this:
el.id = 'my-id'

// if the property does not exist (and in a few special cases), we set as an attribute instead:
el.setAttribute('custom-attribute', 'my-value')

Now, how does this relate to the reported issue? username and password are actually special DOM properties on anchor elements - and they do exactly what you see here: get/set the username & password from/for the href. But they don't do this if set as attributes - it only works when being set through Javascript as DOM properties.

So in a way, this behavior is unsurprising, assuming one was aware of these special properties (I wasn't as of 5 minutes ago) and Vue's default for setting properties.

It has an easy workaround/fix: force setting these as attributes with .attr:

https://play.vuejs.org/#eNp9kU1vwjAMhv9KlwsXaLWPU9UhbYjDJu1D246RplBMW0jjLHEoGuK/zymCcUDcHD9vosfOVjxYm64DiFwUvnSNpcQDBTuWpsj2DS75QNBarQj4lCSFSmoHi3spaiLr8yzrui6tECsNaYmtFEkePDijWkgVkePkYIE4U24QmVXed+jmRzZTvxF4bGGEVIMbRdLMAgHjn7CRYjzRTblKXuCqyFSvd6IkhoJ8iWbRVOnSo+FxtlFUCraxjQb3ZqlB46XIk55EprTG7rnvkQswPPTLGsrVmf7Ss0fOxbsDnm4NUhwZKVcB7fH08xU2XB9hi/OgOX0BfoBHHaLjPvYYzJy1T3K97VNr0VFjqi8/3RAYfxgqisbkrs9LwX86uTD6v+5tetffk2bHW/xeg4tv8gIZpDfXYvcHoxq1Iw==

Now we just have to discuss if this needs to be handled as another special case in shouldSetAsProp, or if we see this as default behavior in Vue 3:

https://github.com/vuejs/core/blob/3648498ae55e239a54fff710a923531d16bde971/packages/runtime-dom/src/patchProp.ts#L69

LinusBorg avatar Mar 11 '24 21:03 LinusBorg