diff --git a/.changeset/eleven-cycles-applaud.md b/.changeset/eleven-cycles-applaud.md
new file mode 100644
index 000000000000..3e73a89252e9
--- /dev/null
+++ b/.changeset/eleven-cycles-applaud.md
@@ -0,0 +1,5 @@
+---
+"svelte": patch
+---
+
+breaking: preserve slots inside templates with a shadowrootmode attribute
diff --git a/packages/svelte/src/compiler/phases/1-parse/state/element.js b/packages/svelte/src/compiler/phases/1-parse/state/element.js
index f40bccd44421..16960e9721e6 100644
--- a/packages/svelte/src/compiler/phases/1-parse/state/element.js
+++ b/packages/svelte/src/compiler/phases/1-parse/state/element.js
@@ -51,6 +51,23 @@ function parent_is_head(stack) {
return false;
}
+/** @param {import('#compiler').TemplateNode[]} stack */
+function parent_is_shadowroot_template(stack) {
+ // https://developer.chrome.com/docs/css-ui/declarative-shadow-dom#building_a_declarative_shadow_root
+ let i = stack.length;
+ while (i--) {
+ if (
+ stack[i].type === 'RegularElement' &&
+ /** @type {import('#compiler').RegularElement} */ (stack[i]).attributes.some(
+ (a) => a.type === 'Attribute' && a.name === 'shadowrootmode'
+ )
+ ) {
+ return true;
+ }
+ }
+ return false;
+}
+
const regex_closing_textarea_tag = /^<\/textarea(\s[^>]*)?>/i;
const regex_closing_comment = /-->/;
const regex_capital_letter = /[A-Z]/;
@@ -112,7 +129,8 @@ export default function tag(parser) {
? 'Component'
: name === 'title' && parent_is_head(parser.stack)
? 'TitleElement'
- : name === 'slot'
+ : // TODO Svelte 6/7: once slots are removed in favor of snippets, always keep slot as a regular element
+ name === 'slot' && !parent_is_shadowroot_template(parser.stack)
? 'SlotElement'
: 'RegularElement';
diff --git a/packages/svelte/tests/parser-modern/samples/template-shadowroot/input.svelte b/packages/svelte/tests/parser-modern/samples/template-shadowroot/input.svelte
new file mode 100644
index 000000000000..bcac79a03c51
--- /dev/null
+++ b/packages/svelte/tests/parser-modern/samples/template-shadowroot/input.svelte
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/svelte/tests/parser-modern/samples/template-shadowroot/output.json b/packages/svelte/tests/parser-modern/samples/template-shadowroot/output.json
new file mode 100644
index 000000000000..eb9ffe51de07
--- /dev/null
+++ b/packages/svelte/tests/parser-modern/samples/template-shadowroot/output.json
@@ -0,0 +1,160 @@
+{
+ "css": null,
+ "js": [],
+ "start": 0,
+ "end": 125,
+ "type": "Root",
+ "fragment": {
+ "type": "Fragment",
+ "nodes": [
+ {
+ "type": "RegularElement",
+ "start": 0,
+ "end": 66,
+ "name": "template",
+ "attributes": [
+ {
+ "type": "Attribute",
+ "start": 10,
+ "end": 31,
+ "name": "shadowrootmode",
+ "value": [
+ {
+ "start": 26,
+ "end": 30,
+ "type": "Text",
+ "raw": "open",
+ "data": "open"
+ }
+ ]
+ }
+ ],
+ "fragment": {
+ "type": "Fragment",
+ "nodes": [
+ {
+ "type": "Text",
+ "start": 32,
+ "end": 34,
+ "raw": "\n\t",
+ "data": "\n\t"
+ },
+ {
+ "type": "RegularElement",
+ "start": 34,
+ "end": 54,
+ "name": "p",
+ "attributes": [],
+ "fragment": {
+ "type": "Fragment",
+ "nodes": [
+ {
+ "type": "RegularElement",
+ "start": 37,
+ "end": 50,
+ "name": "slot",
+ "attributes": [],
+ "fragment": {
+ "type": "Fragment",
+ "nodes": [],
+ "transparent": true
+ }
+ }
+ ],
+ "transparent": true
+ }
+ },
+ {
+ "type": "Text",
+ "start": 54,
+ "end": 55,
+ "raw": "\n",
+ "data": "\n"
+ }
+ ],
+ "transparent": true
+ }
+ },
+ {
+ "type": "Text",
+ "start": 66,
+ "end": 67,
+ "raw": "\n",
+ "data": "\n"
+ },
+ {
+ "type": "RegularElement",
+ "start": 67,
+ "end": 111,
+ "name": "template",
+ "attributes": [],
+ "fragment": {
+ "type": "Fragment",
+ "nodes": [
+ {
+ "type": "Text",
+ "start": 77,
+ "end": 79,
+ "raw": "\n\t",
+ "data": "\n\t"
+ },
+ {
+ "type": "RegularElement",
+ "start": 79,
+ "end": 99,
+ "name": "p",
+ "attributes": [],
+ "fragment": {
+ "type": "Fragment",
+ "nodes": [
+ {
+ "type": "SlotElement",
+ "start": 82,
+ "end": 95,
+ "name": "slot",
+ "attributes": [],
+ "fragment": {
+ "type": "Fragment",
+ "nodes": [],
+ "transparent": true
+ }
+ }
+ ],
+ "transparent": true
+ }
+ },
+ {
+ "type": "Text",
+ "start": 99,
+ "end": 100,
+ "raw": "\n",
+ "data": "\n"
+ }
+ ],
+ "transparent": true
+ }
+ },
+ {
+ "type": "Text",
+ "start": 111,
+ "end": 112,
+ "raw": "\n",
+ "data": "\n"
+ },
+ {
+ "type": "SlotElement",
+ "start": 112,
+ "end": 125,
+ "name": "slot",
+ "attributes": [],
+ "fragment": {
+ "type": "Fragment",
+ "nodes": [],
+ "transparent": true
+ }
+ }
+ ],
+ "transparent": false
+ },
+ "options": null
+}