Open
Description
Describe the bug
Bug Report: Double declaration of $$slots when using $props() with named slots
When using Svelte 5's runes and $props()
in a component that has named slots and spreads remaining props, the compiler generates code that declares $$slots
twice, causing a build error.
Expected Behavior
The component should compile successfully since $$slots
is a special Svelte variable that should be handled by the runtime.
Actual Behavior
The compiled output tries to declare $$slots
twice:
- First from
sanitize_slots($$props)
- Then again when destructuring from
$props()
Additional Context
- This only occurs when using named slots (
<slot name="x">
) - This happens when using
$props()
with runes enabled - The issue appears to be in how the compiler handles the interaction between runes'
$props()
and Svelte's built-in slot handling
Workarounds
There are two ways to work around this issue:
Don't use prop spreading in components with named slots:
<script>
const { class: className = '' } = $props();
// Don't use ...rest
</script>
<div class="slot-test {className}">
<slot name="header" />
</div>
Don't use $props() in components that need both named slots and prop spreading:
<script>
export let className = '';
// Use traditional props instead of $props()
</script>
<div {...$$restProps} class="slot-test {className}">
<slot name="header" />
</div>
Reproduction
- Create a component that uses runes,
$props()
, and named slots:
<!-- SlotTest.svelte -->
<svelte:options runes={true} />
<script lang="ts">
const { class: className = '', ...rest } = $props();
</script>
<div {...rest} class="slot-test {className}">
{#if $$slots.header}
<div class="header">
<slot name="header" />
</div>
{/if}
{#if $$slots.footer}
<div class="footer">
<slot name="footer" />
</div>
{/if}
</div>
- Use the component with named slots:
<!-- App.svelte -->
<script>
import SlotTest from './SlotTest.svelte';
</script>
<SlotTest data-testid="test">
<svelte:fragment slot="header">
Header Content
</svelte:fragment>
<svelte:fragment slot="footer">
Footer Content
</svelte:fragment>
</SlotTest>
Logs
error during build:
Identifier "$$slots" has already been declared
7: export default function SlotTest($$payload, $$props) {
8: const $$slots = $.sanitize_slots($$props);
9: const { $$slots, $$events, ...props } = $$props;
^
System Info
System:
OS: macOS 15.4.1
CPU: (12) arm64 Apple M2 Max
Memory: 3.31 GB / 64.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 20.17.0 - ~/.nvm/versions/node/v20.17.0/bin/node
Yarn: 1.22.22 - ~/.yarn/bin/yarn
npm: 10.8.2 - ~/.nvm/versions/node/v20.17.0/bin/npm
pnpm: 10.8.1 - ~/.nvm/versions/node/v20.17.0/bin/pnpm
Watchman: 2025.04.07.00 - /opt/homebrew/bin/watchman
Browsers:
Brave Browser: 130.1.71.118
Chrome: 135.0.7049.115
Safari: 18.4
npmPackages:
svelte: ^5.20.2 => 5.25.10
Severity
blocking an upgrade
Metadata
Metadata
Assignees
Labels
No labels