-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
$$slots with conditional/reactive content? #5312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hello everyone! I am writing a component library for mobile phones. This is an important function, is there any temporary solution at the moment? This is my situation,the leader icon cannot be rendered correctly: <ListItem>
{#if item.active }
<Icon name="active_icon" slot="leading" />
{/if}
<h4>{ item.title }</h4>
<p>{ item.desc }</p>
<Icon slot="trailing" name="more_vert" />
</ListItem> Thank you! I currently convert the dom structure, but there is one more level of nesting: <div slot="leading">
{#if item.active }
<Icon name="active_icon" />
{/if}
</div> Update, no extra nesting, but <svelte:fragment slot="leading">
{#if item.active }
<Icon name="active_icon" />
{/if}
</svelte:fragment> |
What about `$$slots`` containing the textContent of the slot? Pros:
Cons:
|
What about having references to the passed objects in the <MyComponent>
<div id="my-div" slot="slot1">Some content</div>
</MyComponent>
|
Just ran into this issue myself. Spent far too much time debugging this only to eventually come across this issue. Doesn't seem this issue is getting much (if any) attention. At the least, the current documentation should be updated to call out that {#if $$slots.description}
<!-- This <hr> and slot will render only if a slot named "description" is provided. -->
<hr>
<slot name="description"></slot>
{/if} will only work if the element with Currently, instead of being able to utilize |
Here's a simple spike demonstrating the problem: https://svelte.dev/repl/94f5623ac9e54ce4918362492c6e35f1?version=3.42.6 I'm not sure if it would be possible to check the content length of the slot but that would solve my current situation. This really limits the ability to have fallback content, especially at any sort depth beyond 1. |
in malinajs it's solved by #fragment - https://malinajs.github.io/repl/#/share/TJLjJATAvKX?version=0.6.39 |
I guess, this also has a side effect of a slot fallback not being shown for:
|
Forwarding slots as empty with https://svelte.dev/repl/cc6ab0a9bb714232b8b3af335db03792?version=3.48.0 This one of the details about svelte that severely limits the reuseability and composeability of components because the |
Here is a work around that works fine for me with Svelte 4. Deepest component too-deep.svelte <script lang="ts">
export let backgroundEnabled: boolean;
export let hoverBackgroundEnabled: boolean;
</script>
{#if backgroundEnabled} // we are checking a boolean flag here, not the
<div class='entryBackground'>
<slot name="background" />
</div>
{/if}
{#if hoverBackgroundEnabled} // same
<div class='entryHoverBackground'>
<slot name="hoverBackground" />
</div>
{/if} Intermediate component boss.svelte <script lang="ts">
import ConditionalContent from './too-deep.svelte'
</script>
<div>
This is the boss div content
<!-- Notice how we map the slot checks to the boolean flags in this layer -->
<ConditionalContent backgroundEnabled={$$slots.background} entryHoverBackground={$$slots.hoverBackground}>
<slot name="background" slot="background" />
<slot name="hoverBackground" slot="hoverBackground" />
</ConditionalContent>
</div> Top level component top-layer.svelte <script lang="ts">
import Boos from './boss.svelte'
</script>
<div>
<Boos>
<svelte:fragment slot="background">
My background content
</svelte:fragment>
<svelte:fragment slot="hoverBackground">
My hover background content
</svelte:fragment>
</Boos>
<Boos>
<svelte:fragment slot="hoverBackground">
My second hover background content
</svelte:fragment>
</Boos>
<Boos>
<svelte:fragment slot="background">
My second background content
</svelte:fragment>
</Boos>
</div> That will give you the result you would expect. For slots that hasn't been provided in the top-layer, they won't be rendered in the too-deep layer |
Closing since |
The new
$$slots
feature (thanks to @tanhauhau) provides information if a slot is loaded/filled or empty.However this only works with "static" content. As soon as there is a condition
{#if}
or{#await}
involved thethe output of
$$slots
is not really useful anymore or in case of a named slot a error is thrown.In case of an unnamed slot in combination with
{#if}
the slot is considered filled and$$slots.default
results totrue
even if the condition passed to the slot is false. Additionally the fallback wont be rendered.
In case of a named slot value inside a
{#if}
(example below) the line<div slot="a">Content</div>
will throwValidationError: Element with a slot='...' attribute must be a child of a component or a descendant of a custom element
Example (tested with
commit 8adb47401e7f7b420ffabf9752a8236114aaecfc
)The behaviors that I would expect, want and need are:
$$slot
are only set to true if the content passed to a slot is renderable.Why would I want that?
One usecase (besides many others) is implicitly setting the state of a component with a slot.
Example:
I have a Card component that displays data coming from a fetch request. The Card component should have a
loading
state while it is fetching and go to itsdefault
state if the data is fetched and rendered.At the moment the only way i konw of is to explicitly create a
loading
variable, set it totrue
before fetching, set it tofalse
afterwards and pass it down to the
Card
component.This is okay if you have to do it one or twice but not if you have many components with similar structure.
With a properly reactive
$$slots
property this could be much cleaner and could look something like this:Thats it.
Thanks you for providing such an awesome tool.
The text was updated successfully, but these errors were encountered: