${$.escape(title)}
we don't need to traverse these nodes
or
these
ones
${$.html(content)}these
trailing
nodes
can
be
completely
ignored
diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js
index 2928ca9173..4c248cb19c 100644
--- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js
+++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js
@@ -7,7 +7,7 @@ import { dev, locator } from '../../../../state.js';
import * as b from '#compiler/builders';
import { clean_nodes, determine_namespace_for_children } from '../../utils.js';
import { build_element_attributes } from './shared/element.js';
-import { process_children, build_template } from './shared/utils.js';
+import { process_children, build_template, build_attribute_value } from './shared/utils.js';
/**
* @param {AST.RegularElement} node
@@ -71,6 +71,42 @@ export function RegularElement(node, context) {
);
}
+ let select_with_value = false;
+
+ if (node.name === 'select') {
+ const value = node.attributes.find(
+ (attribute) =>
+ ((attribute.type === 'Attribute' || attribute.type === 'BindDirective') &&
+ attribute.name === 'value') ||
+ attribute.type === 'SpreadAttribute'
+ );
+ if (value) {
+ select_with_value = true;
+ const left = b.id('$$payload.select_value');
+ if (value.type === 'SpreadAttribute') {
+ state.template.push(
+ b.stmt(b.assignment('=', left, b.member(value.expression, 'value', false, true)))
+ );
+ } else if (value.type === 'Attribute') {
+ state.template.push(
+ b.stmt(b.assignment('=', left, build_attribute_value(value.value, context)))
+ );
+ } else if (value.type === 'BindDirective') {
+ state.template.push(
+ b.stmt(
+ b.assignment(
+ '=',
+ left,
+ value.expression.type === 'SequenceExpression'
+ ? b.call(value.expression.expressions[0])
+ : value.expression
+ )
+ )
+ );
+ }
+ }
+ }
+
if (body === null) {
process_children(trimmed, { ...context, state });
} else {
@@ -96,6 +132,10 @@ export function RegularElement(node, context) {
);
}
+ if (select_with_value) {
+ state.template.push(b.stmt(b.assignment('=', b.id('$$payload.select_value'), b.void0)));
+ }
+
if (!node_is_void) {
state.template.push(b.literal(`${node.name}>`));
}
diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js
index b0bcb8fd6f..e57afbb42a 100644
--- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js
+++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js
@@ -236,6 +236,16 @@ export function build_element_attributes(node, context) {
);
}
+ if (node.name === 'option' && name === 'value') {
+ context.state.template.push(
+ b.call(
+ '$.maybe_selected',
+ b.id('$$payload'),
+ literal_value != null ? b.literal(/** @type {any} */ (literal_value)) : b.void0
+ )
+ );
+ }
+
continue;
}
@@ -260,6 +270,10 @@ export function build_element_attributes(node, context) {
b.call('$.attr', b.literal(name), value, is_boolean_attribute(name) && b.true)
);
}
+
+ if (name === 'value' && node.name === 'option') {
+ context.state.template.push(b.call('$.maybe_selected', b.id('$$payload'), value));
+ }
}
}
diff --git a/packages/svelte/src/internal/server/index.js b/packages/svelte/src/internal/server/index.js
index 29e09fe4dd..a815d0755e 100644
--- a/packages/svelte/src/internal/server/index.js
+++ b/packages/svelte/src/internal/server/index.js
@@ -535,3 +535,12 @@ export function derived(fn) {
return updated_value;
};
}
+
+/**
+ *
+ * @param {Payload} payload
+ * @param {*} value
+ */
+export function maybe_selected(payload, value) {
+ return value === payload.select_value ? ' selected' : '';
+}
diff --git a/packages/svelte/src/internal/server/payload.js b/packages/svelte/src/internal/server/payload.js
index 8df5787ba4..a31120ae16 100644
--- a/packages/svelte/src/internal/server/payload.js
+++ b/packages/svelte/src/internal/server/payload.js
@@ -18,6 +18,7 @@ export class Payload {
css = new Set();
out = '';
uid = () => '';
+ select_value = undefined;
head = new HeadPayload();
diff --git a/packages/svelte/tests/runtime-legacy/samples/select-in-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/select-in-each/_config.js
index 335c46d53d..842d8e855c 100644
--- a/packages/svelte/tests/runtime-legacy/samples/select-in-each/_config.js
+++ b/packages/svelte/tests/runtime-legacy/samples/select-in-each/_config.js
@@ -4,7 +4,7 @@ import { ok, test } from '../../test';
export default test({
html: `
selected: a
diff --git a/packages/svelte/tests/server-side-rendering/samples/select-value/_expected.html b/packages/svelte/tests/server-side-rendering/samples/select-value/_expected.html
new file mode 100644
index 0000000000..96d1d8b233
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/select-value/_expected.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/svelte/tests/server-side-rendering/samples/select-value/main.svelte b/packages/svelte/tests/server-side-rendering/samples/select-value/main.svelte
new file mode 100644
index 0000000000..811d752d4e
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/select-value/main.svelte
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/server/index.svelte.js
index a587c05e2c..0532ec5aa9 100644
--- a/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/server/index.svelte.js
+++ b/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/server/index.svelte.js
@@ -3,5 +3,5 @@ import * as $ from 'svelte/internal/server';
export default function Skip_static_subtree($$payload, $$props) {
let { title, content } = $$props;
- $$payload.out += ` we don't need to traverse these nodes or these ones these trailing nodes can be completely ignored${$.escape(title)}
we don't need to traverse these nodes
or
these
ones
${$.html(content)}these
trailing
nodes
can
be
completely
ignored