From 6f392d679bc5c4790aad8bfc1135c7f88c6ae510 Mon Sep 17 00:00:00 2001
From: Simon H <5968653+dummdidumm@users.noreply.github.com>
Date: Wed, 5 Feb 2025 20:22:36 +0100
Subject: [PATCH] fix: properly set `value` property of custom elements
(#15206)
Avoid going through the `element.value = element.__value = newValue` condition because `__value` is actually how Lit stores the current value on the element, and messing with that would break things: Lit would think the value hasn't changed (because `__value` is already set to the new value by us) and doesn't fire an update.
fixes #15194
---
.changeset/great-planes-swim.md | 5 +++++
.../client/dom/elements/attributes.js | 7 ++++---
.../custom-element-attributes/_config.js | 13 ++++++++----
.../custom-element-attributes/main.svelte | 20 +++++++++++++++++++
4 files changed, 38 insertions(+), 7 deletions(-)
create mode 100644 .changeset/great-planes-swim.md
diff --git a/.changeset/great-planes-swim.md b/.changeset/great-planes-swim.md
new file mode 100644
index 0000000000..ecf8fa17aa
--- /dev/null
+++ b/.changeset/great-planes-swim.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: properly set `value` property of custom elements
diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js
index eab27e6c02..8c86fe7e02 100644
--- a/packages/svelte/src/internal/client/dom/elements/attributes.js
+++ b/packages/svelte/src/internal/client/dom/elements/attributes.js
@@ -363,9 +363,10 @@ export function set_attributes(
element.style.cssText = value + '';
} else if (key === 'autofocus') {
autofocus(/** @type {HTMLElement} */ (element), Boolean(value));
- } else if (key === '__value' || (key === 'value' && value != null)) {
- // @ts-ignore
- element.value = element[key] = element.__value = value;
+ } else if (!is_custom_element && (key === '__value' || (key === 'value' && value != null))) {
+ // @ts-ignore We're not running this for custom elements because __value is actually
+ // how Lit stores the current value on the element, and messing with that would break things.
+ element.value = element.__value = value;
} else if (key === 'selected' && is_option_element) {
set_selected(/** @type {HTMLOptionElement} */ (element), value);
} else {
diff --git a/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/_config.js b/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/_config.js
index 118a51157e..7f406d8f0d 100644
--- a/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/_config.js
+++ b/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/_config.js
@@ -1,19 +1,24 @@
import { test } from '../../test';
export default test({
- mode: ['client', 'server'],
+ mode: ['client'],
async test({ assert, target }) {
const my_element = /** @type HTMLElement & { object: { test: true }; } */ (
target.querySelector('my-element')
);
- const my_link = /** @type HTMLAnchorElement & { object: { test: true }; } */ (
- target.querySelector('a')
- );
assert.equal(my_element.getAttribute('string'), 'test');
assert.equal(my_element.hasAttribute('object'), false);
assert.deepEqual(my_element.object, { test: true });
+
+ const my_link = /** @type HTMLAnchorElement & { object: { test: true }; } */ (
+ target.querySelector('a')
+ );
assert.equal(my_link.getAttribute('string'), 'test');
assert.equal(my_link.hasAttribute('object'), false);
assert.deepEqual(my_link.object, { test: true });
+
+ const [value1, value2] = target.querySelectorAll('value-element');
+ assert.equal(value1.shadowRoot?.innerHTML, 'test');
+ assert.equal(value2.shadowRoot?.innerHTML, 'test');
}
});
diff --git a/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte b/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte
index ff94a9484c..4c98245e5b 100644
--- a/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte
+++ b/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte
@@ -1,2 +1,22 @@
+
+
+
+
+