Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No conversion from kebab-case to camelCase for property binding #13055

Open
padcom opened this issue Mar 17, 2025 · 4 comments · May be fixed by #13085
Open

No conversion from kebab-case to camelCase for property binding #13055

padcom opened this issue Mar 17, 2025 · 4 comments · May be fixed by #13085
Labels
🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. has workaround A workaround has been found to avoid the problem

Comments

@padcom
Copy link

padcom commented Mar 17, 2025

Vue version

3.5.13

Link to minimal reproduction

https://github.com/padcom/vue-property-mapping-bug

Steps to reproduce

npm install
npm start

What is expected?

When dot-binding to a property the conversion from kebab-case to camelCase should happen just as well as when it is with v-bind-ing attributes.

There is an ESLint rule (vue/attribute-hyphenation) that has no separate configuration for prop vs attr binding, which makes me assume both should work the same.

What is actually happening?

When binding using property binding with a .test-prop the actual assigned property is test-prop instead of testProp as it would be with attribute binding.

System Info

Google CHrome 134.0.6998.88 (Official Build) (64-bit)

Any additional comments?

I am not sure how this should be handled. There are at least two options:

  • make it work the same for both colon binding to attributes and dot binding for properties where the kebab-case to camelCase conversion happens automatically for both Vue.js component and HTMLElement
  • change the ESLint rule to be aware of this conversion misalignment and issue the warning only when it makes sense.
@padcom
Copy link
Author

padcom commented Mar 17, 2025

I think the main problem is the ESLint rule. What happens is, if one has this rule enabled with auto-fix, then the code from valid (.testProp="someReactiveValue") is changed to something that is invalid (.test-prop="someReactiveValue").

This forces the use of <!-- eslint-disable-next-line vue/attribute-hyphenation --> or else it'll be either an error or an assignment to a non-existent property of the target object.

@edison1105 edison1105 added has workaround A workaround has been found to avoid the problem 🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. labels Mar 17, 2025
@padcom
Copy link
Author

padcom commented Mar 17, 2025

the workaround is to add the .camel modifier, e.g. .test-prop.camel="someReactiveValue".

@vonBrax
Copy link

vonBrax commented Mar 18, 2025

I'm running into a similar problem because of attribute name casing convention, and from what I found, there's a lot of people having similar issues.

I found these 2 comments that better describe the issue and point to a possible fix:

vuejs/docs#1972 (comment)
vuejs/docs#1972 (comment)

My specific use case is, I have a Vue component library that wraps a Custom Element library, like for example:

class MyElement extends HTMLElement {
  ...

  // Reflect primitive values
  get someString() {
    return this.getAttribute('some-string');
  }

  set someString(value) {
    if (value) this.setAttribute('some-string, value);
    else this.removeAttribute('some-string);
  }

  // Don't reflect complex objects
  get someComplexObject() {
    return this._someComplexObject;
  }

  set someComplextObject(value) {
    this._someComplextObject = value;
  }
}
<script setup lang="ts">
import './MyElement.js';

defineProps<{
  someString: string;
  someComplexObject: Record<string, string>;
}>();
</script>

<template>
  <my-element :some-string :some-complex-object></my-element>
</template>

In this example, the some-complex-object binding won't work, because Vue searches for 'some-complex-object' in MyElement (instead of 'someComplexObject' in MyElement), which returns false, and then ends up setting the object as an attribute, which renders as:

<my-element some-complex-object="[object Object]"></my-element>

So the alternatives are:

  1. Use camelCase and disable vue/attribute-hyphenation or
  2. Use .camel modifier for all hyphenated attribute bindings or
  3. Find all hyphenated attributes that accept a complex data type and only add the .camel modifier for those

None of these seem very appealing to me. Since Vue does already case conversion in a lot of places, why not here as well to make our lifes easier?

I'm assuming that changing:

to:

return camelize(key) in el || key in el;

would fix this issue without introducing any breaking changes.

I'm happy to open a PR if that would be an acceptable solution.

@edison1105
Copy link
Member

@vonBrax PR welcome!

vonBrax added a commit to vonBrax/vuejs-core that referenced this issue Mar 21, 2025
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. has workaround A workaround has been found to avoid the problem
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants