I have a svelte component with a default slot and a named slot. I have an instance of that component and use the named slot, and use the default slow inside an {#if} statement checking for a boolean.
The problem is inside my component, I have logic that checks for the default slot and renders some padding and border. It seems even when the boolean is false and the {#if} is false, that the default slow is still there, just empty.
Child:
const hasDefaultSlot = Object.keys($$slots).includes('default');
Parent:
<MyComponent>
<div slot="header"> header </div>
{#if checked}
<div>body</div>
{/if}
</MyComponent>
My expectation is that when checked
is false, Object.keys($$slots).includes('default')
would be false, or $$slots.default
would be false, or that $$slots.default
wouldn't be a boolean, but an object that contains other info that I can use to check if it's empty.
Sadly, it seems the Svelte compiler sees the #if
statement result as always true, even though it changes in real time and starts off false.
Without being able to conditionally detect the slot, I am always rendering the body and body styles for a card item, which messes up the css for the component.
Everything inside the component that is not explicitly assigned to a named slot becomes part of the default slot. The {#if}
is also part of the slot, so the slot will always be set.
You can work around this by adding an additional flag property as you mentioned.
In Svelte 5 this will be a bit different with the more flexible snippets system. Like with the default slot there is an implicit assignment to a children
property but this property can be assigned like any other, so the contents can be passed conditionally.
{#snippet body()}
<div>body</div>
{/snippet}
<MyComponent children={checked ? body : undefined}>
{#snippet header()}
<div>header</div>
{/snippet}
</MyComponent>