diff --git a/.changeset/tricky-planets-rush.md b/.changeset/tricky-planets-rush.md
new file mode 100644
index 000000000000..aa93098b9f55
--- /dev/null
+++ b/.changeset/tricky-planets-rush.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: recognize option value on spread attribute
diff --git a/packages/svelte/src/compiler/compile/nodes/Element.js b/packages/svelte/src/compiler/compile/nodes/Element.js
index 0ee4f26d5f74..248f831f66ea 100644
--- a/packages/svelte/src/compiler/compile/nodes/Element.js
+++ b/packages/svelte/src/compiler/compile/nodes/Element.js
@@ -1,5 +1,6 @@
import { is_html, is_svg, is_void } from '../../../shared/utils/names.js';
import Node from './shared/Node.js';
+import { walk } from 'estree-walker';
import Attribute from './Attribute.js';
import Binding from './Binding.js';
import EventHandler from './EventHandler.js';
@@ -430,7 +431,7 @@ export default class Element extends Node {
}
if (this.name === 'textarea') {
if (info.children.length > 0) {
- const value_attribute = info.attributes.find((node) => node.name === 'value');
+ const value_attribute = get_value_attribute(info.attributes);
if (value_attribute) {
component.error(value_attribute, compiler_errors.textarea_duplicate_value);
return;
@@ -449,7 +450,7 @@ export default class Element extends Node {
// Special case — treat these the same way:
//
//
- const value_attribute = info.attributes.find((attribute) => attribute.name === 'value');
+ const value_attribute = get_value_attribute(info.attributes);
if (!value_attribute) {
info.attributes.push({
type: 'Attribute',
@@ -1420,3 +1421,30 @@ function within_custom_element(parent) {
}
return false;
}
+
+/**
+ * @param {any[]} attributes
+ */
+function get_value_attribute(attributes) {
+ let node_value;
+ attributes.forEach((node) => {
+ if (node.type !== 'Spread' && node.name.toLowerCase() === 'value') {
+ node_value = node;
+ }
+ if (node.type === 'Spread') {
+ walk(/** @type {any} */ (node.expression), {
+ enter(/** @type {import('estree').Node} */ node) {
+ if (node_value) {
+ this.skip();
+ }
+ if (node.type === 'Identifier') {
+ if (/** @type {import('estree').Identifier} */ (node).name.toLowerCase() === 'value') {
+ node_value = node;
+ }
+ }
+ }
+ });
+ }
+ });
+ return node_value;
+}
diff --git a/packages/svelte/test/runtime/samples/select-options-spread-attributes/_config.js b/packages/svelte/test/runtime/samples/select-options-spread-attributes/_config.js
new file mode 100644
index 000000000000..be4faba61202
--- /dev/null
+++ b/packages/svelte/test/runtime/samples/select-options-spread-attributes/_config.js
@@ -0,0 +1,7 @@
+export default {
+ html: `
+
+ `
+};
diff --git a/packages/svelte/test/runtime/samples/select-options-spread-attributes/main.svelte b/packages/svelte/test/runtime/samples/select-options-spread-attributes/main.svelte
new file mode 100644
index 000000000000..cabaf2ea0a7f
--- /dev/null
+++ b/packages/svelte/test/runtime/samples/select-options-spread-attributes/main.svelte
@@ -0,0 +1,3 @@
+