Repository: sveltejs/svelte (2025-08-09T22:14:02Z)

Issue:
Set custom element data fails when using builtin custom elements.
### Describe the bug

The helper `set_custom_element_data` only checks for autonomous custom elements but fails to check for builtin custom elements (`is` attribute) [here](https://github.com/sveltejs/svelte/blob/d2ba2589fee2ec6985c0fe0fbd800ab34518378e/packages/svelte/src/internal/client/dom/elements/attributes.js#L244), so it always set the value as attribute.

### Reproduction

https://svelte.dev/playground/46f14880c73443318e26dd375ff3c0d2

### Logs

```shell

```

### System Info

```shell
REPL
```

### Severity

annoyance


Discussion:

Patch:
diff --git a/.changeset/fuzzy-shrimps-dream.md b/.changeset/fuzzy-shrimps-dream.md
new file mode 100644
index 000000000000..0ddab531acb5
--- /dev/null
+++ b/.changeset/fuzzy-shrimps-dream.md
@@ -0,0 +1,5 @@
+---
+"svelte": patch
+---
+
+fix: Add check for builtin custom elements in `set_custom_element_data`
diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js
index 2fa5d4541c48..a5b7140f2538 100644
--- a/packages/svelte/src/internal/client/dom/elements/attributes.js
+++ b/packages/svelte/src/internal/client/dom/elements/attributes.js
@@ -238,10 +238,10 @@ export function set_custom_element_data(node, prop, value) {
 			// Don't compute setters for custom elements while they aren't registered yet,
 			// because during their upgrade/instantiation they might add more setters.
 			// Instead, fall back to a simple "an object, then set as property" heuristic.
-			(setters_cache.has(node.nodeName) ||
+			(setters_cache.has(node.getAttribute('is') || node.nodeName) ||
 			// customElements may not be available in browser extension contexts
 			!customElements ||
-			customElements.get(node.tagName.toLowerCase())
+			customElements.get(node.getAttribute('is') || node.tagName.toLowerCase())
 				? get_setters(node).includes(prop)
 				: value && typeof value === 'object')
 		) {
@@ -546,9 +546,10 @@ var setters_cache = new Map();
 
 /** @param {Element} element */
 function get_setters(element) {
-	var setters = setters_cache.get(element.nodeName);
+	var cache_key = element.getAttribute('is') || element.nodeName;
+	var setters = setters_cache.get(cache_key);
 	if (setters) return setters;
-	setters_cache.set(element.nodeName, (setters = []));
+	setters_cache.set(cache_key, (setters = []));
 
 	var descriptors;
 	var proto = element; // In the case of custom elements there might be setters on the instance


Test patch:
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 7f406d8f0d28..3d8917c1479e 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
@@ -20,5 +20,8 @@ export default test({
 		const [value1, value2] = target.querySelectorAll('value-element');
 		assert.equal(value1.shadowRoot?.innerHTML, '<span>test</span>');
 		assert.equal(value2.shadowRoot?.innerHTML, '<span>test</span>');
+
+		const value_builtin = target.querySelector('div');
+		assert.equal(value_builtin?.shadowRoot?.innerHTML, '<span>test</span>');
 	}
 });
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 82774f160d3b..badb8f96c756 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
@@ -15,6 +15,24 @@
 			}
 		});
 	}
+	if(!customElements.get('value-builtin')) {
+		customElements.define('value-builtin', class extends HTMLDivElement {
+
+			constructor() {
+				super();
+				this.attachShadow({ mode: 'open' });
+			}
+
+			set value(v) {
+				if (this.__value !== v) {
+					this.__value = v;
+					this.shadowRoot.innerHTML = `<span>${v}</span>`;
+				}
+			}
+		}, {
+			extends: 'div'
+		});
+	}
 </script>
 
 <my-element string="test" object={{ test: true }}></my-element>
@@ -22,3 +40,4 @@
 
 <value-element value="test"></value-element>
 <value-element {...{value: "test"}}></value-element>
+<div is="value-builtin" value="test"></div>