Repository: sveltejs/svelte (JavaScript)

Issue:
Draw transition not working without event
### Describe the bug

The `transition:draw` transition only works when an event (like `onintrostart={()=>{}}`) is present on the element

### Reproduction

https://svelte.dev/playground/b9bdc21015264d19ba6b0af6d506016d?version=5.1.7

### Logs

_No response_

### System Info

```shell
System:
    OS: Windows 11 10.0.22631
    CPU: (12) x64 Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz
    Memory: 15.85 GB / 31.93 GB
  Binaries:
    Node: 20.15.1 - ~\AppData\Local\pnpm\node.EXE
    npm: 10.7.0 - ~\AppData\Local\pnpm\npm.CMD
    pnpm: 9.10.0 - ~\AppData\Local\pnpm\pnpm.EXE
  Browsers:
    Edge: Chromium (127.0.2651.74)
    Internet Explorer: 11.0.22621.3527
  npmPackages:
    svelte: ^5.1.7 => 5.1.7
```


### Severity

annoyance


Discussion:

Patch:
diff --git a/.changeset/modern-adults-lay.md b/.changeset/modern-adults-lay.md
new file mode 100644
index 000000000000..9caa3962af14
--- /dev/null
+++ b/.changeset/modern-adults-lay.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: ensure transitions are applied to nested elements
diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js
index 89c2e19c3fa4..f5a31d09a779 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/index.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/index.js
@@ -63,6 +63,7 @@ import { SvelteWindow } from './visitors/SvelteWindow.js';
 import { TaggedTemplateExpression } from './visitors/TaggedTemplateExpression.js';
 import { Text } from './visitors/Text.js';
 import { TitleElement } from './visitors/TitleElement.js';
+import { TransitionDirective } from './visitors/TransitionDirective.js';
 import { UpdateExpression } from './visitors/UpdateExpression.js';
 import { UseDirective } from './visitors/UseDirective.js';
 import { VariableDeclarator } from './visitors/VariableDeclarator.js';
@@ -172,6 +173,7 @@ const visitors = {
 	SvelteWindow,
 	TaggedTemplateExpression,
 	Text,
+	TransitionDirective,
 	TitleElement,
 	UpdateExpression,
 	UseDirective,
diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/TransitionDirective.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/TransitionDirective.js
new file mode 100644
index 000000000000..c218f741c3dc
--- /dev/null
+++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/TransitionDirective.js
@@ -0,0 +1,14 @@
+/** @import { AST } from '#compiler' */
+/** @import { Context } from '../types' */
+
+import { mark_subtree_dynamic } from './shared/fragment.js';
+
+/**
+ * @param {AST.TransitionDirective} node
+ * @param {Context} context
+ */
+export function TransitionDirective(node, context) {
+	mark_subtree_dynamic(context.path);
+
+	context.next();
+}


Test patch:
diff --git a/packages/svelte/tests/runtime-runes/samples/transition-static-subtree/_config.js b/packages/svelte/tests/runtime-runes/samples/transition-static-subtree/_config.js
new file mode 100644
index 000000000000..99563ef95941
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/transition-static-subtree/_config.js
@@ -0,0 +1,23 @@
+import { flushSync } from '../../../../src/index-client.js';
+import { test } from '../../test';
+
+export default test({
+	async test({ assert, raf, target }) {
+		assert.htmlEqual(target.innerHTML, '<button>Toggle</button><div><span>123</span></div>');
+
+		const btn1 = target.querySelector('button');
+		btn1?.click();
+		flushSync();
+		raf.tick(250);
+
+		assert.htmlEqual(
+			target.innerHTML,
+			'<button>Toggle</button><div><span style="opacity: 0.5;">123</span></div>'
+		);
+
+		flushSync();
+		raf.tick(500);
+
+		assert.htmlEqual(target.innerHTML, '<button>Toggle</button>');
+	}
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/transition-static-subtree/main.svelte b/packages/svelte/tests/runtime-runes/samples/transition-static-subtree/main.svelte
new file mode 100644
index 000000000000..4a15e156994e
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/transition-static-subtree/main.svelte
@@ -0,0 +1,18 @@
+<script>
+	function fade(_) {
+		return {
+			duration: 500,
+			css: t => `opacity: ${t}`,
+		}
+	}
+
+	let visible = $state(true);
+</script>
+
+<button onclick={() => visible = !visible}>Toggle</button>
+
+{#if visible}
+	<div>
+		<span transition:fade>123</span>
+	</div>
+{/if}