Skip to content

Commit d1f0389

Browse files
committed
fix: support camelCase properties on custom elements
while attributes are case insensitive, properties are not. to not introduce a breaking change, the lowercased variant is checked first. fixes #9325
1 parent 6f508a0 commit d1f0389

File tree

6 files changed

+44
-4
lines changed

6 files changed

+44
-4
lines changed

.changeset/seven-cars-drum.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: support camelCase properties on custom elements

packages/svelte/src/compiler/compile/render_dom/wrappers/Element/Attribute.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
103103
this.parent.has_dynamic_value = true;
104104
}
105105
}
106-
if (this.parent.node.namespace == namespaces.foreign) {
107-
// leave attribute case alone for elements in the "foreign" namespace
106+
if (this.parent.node.namespace == namespaces.foreign || this.parent.node.name.includes('-')) {
107+
// leave attribute case alone for elements in the "foreign" namespace and for custom elements
108108
this.name = this.node.name;
109109
this.metadata = this.get_metadata();
110110
this.is_indirectly_bound_value = false;

packages/svelte/src/runtime/internal/dom.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,10 @@ export function set_custom_element_data_map(node, data_map) {
480480
/**
481481
* @returns {void} */
482482
export function set_custom_element_data(node, prop, value) {
483-
if (prop in node) {
483+
const lower = prop.toLowerCase(); // for backwards compatibility with existing behavior we do lowercase first
484+
if (lower in node) {
485+
node[lower] = typeof node[lower] === 'boolean' && value === '' ? true : value;
486+
} else if (prop in node) {
484487
node[prop] = typeof node[prop] === 'boolean' && value === '' ? true : value;
485488
} else {
486489
attr(node, prop, value);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default {
2+
skip_if_ssr: true,
3+
skip_if_hydrate: true,
4+
html: `
5+
<my-custom-element>Hello World!</my-custom-element>
6+
`
7+
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<script>
2+
class MyCustomElement extends HTMLElement {
3+
constructor() {
4+
super();
5+
this._obj = null;
6+
}
7+
8+
set camelCase(obj) {
9+
this._obj = obj;
10+
this.render();
11+
}
12+
13+
connectedCallback() {
14+
this.render();
15+
}
16+
17+
render() {
18+
this.innerHTML = 'Hello ' + this._obj.text + '!';
19+
}
20+
}
21+
22+
window.customElements.define('my-custom-element', MyCustomElement);
23+
</script>
24+
25+
<my-custom-element camelCase={{ text: 'World' }} />

packages/svelte/vitest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export default defineConfig({
2020
}
2121
],
2222
test: {
23-
dir: 'test',
23+
dir: 'test/runtime',
2424
reporters: ['dot'],
2525
exclude: [...configDefaults.exclude, '**/samples/**'],
2626
globalSetup: './test/vitest-global-setup.js'

0 commit comments

Comments
 (0)