Closed ghost closed 2 months ago
I would enjoy this feature.
Is there a workaround for now, to have conditional slots? (Except of copy paste..)
+1. this would help make my code less verbose in some cases.
+1, Especially useful for slot forwarding!!! Otherwise there is no way to use the deepest slot fallbacks
https://svelte.dev/repl/7941b94f6c6f42df93aba4d5ef543917?version=3.38.2
I agree, this is a must-have for complex components. Code duplication is one of the largest sources of bugs, please don't make us do it.
Here's the workaround I'm using:
{#if $$slots.header}
<header>
<slot name="header" />
</header>
{/if}
<style>
header {
padding: 16px;
/* ... */
}
header:empty {
display: none;
}
</style>
This means that when you have something like this:
<Demo>
<svelte:fragment slot="header">
{#if condition}
<p>HELLO</p>
{/if}
</svelte:fragment>
</Demo>
You will only see the <header>
– and its padding – when condition
is true.
We just ran into the same thing -- trying to conditionally pass in a slot. Being able to do this makes sense.... In our case, we are trying to conditionally render a slot named "body" within an expandableCard component. If there's no body slot given to expandableCard, just render the header without expander body.
I guess our workaround would be to pass in a Boolean prop to expandableCard called "hasBody", and then conditionally render the expander div that has the <slot name="body">
... clunky but doable.
Hey. It'd be great to get this as a feature.
Even with <svelte:fragment>
the $$slots.name
resolves to true
Issues like this one, the lack of a <svelte:element>
analogous to <svelte:component>
, lack of a simple way to forward all events, impossibility of using actions on components, etc. are some of the rough edges that must be fixed so Svelte can actually be said to be a really mature framework. These things should just work.
Appreciate the CSS tip @lukeed. For anyone using tailwindcss you can do this with the following:
<header class="p-4 empty:p-0">
Well, I currently use this ugly workaround with CSS display instead of if:
`
Also just ran into this, assumed it was a bug rather than a missing feature because it seems like a no brainer. Is there any input from the svelte team on this? Is it due to technical limitations of the compiler? Or do we need an RFC for it? Would love to move it forward.
Is there any progress on getting this over the line? I really don't think that having workarounds is the best way.
+1
This will be really helpful when creating custom component with predefined options and pass fragments to child component.
For example:
I have MyTableComponent
with some classes for SvelteTable
component. To be able to fully use SvelteTable
from my MyTableComponent
, I need to pass 3 slots from MyTableComponent
into MyTableComponent
. Sometimes 0 or only 1 fragment will be overrides.
+1
I think have a workaround. I created a Svelte component that I named SlotFragment.svelte. It conditionally renders a default slot.
{#if $$slots.default}
<slot />
{/if}
For example when composing components, I have component A with a header
slot. The header
slot has some HTML around it that is rendered conditionally on the slot being filled.
I have component B that that renders component A plus some other stuff. Component B provides a header
slot that should be forwarded to component A, plus its own footer
slot.
This syntax in component B works, but causes component A to always think the slot is filled and it renders the additional HTML.
<slot name="header" slot="header" />
So you try to put an #if around it, but the slot must be filled within a component.
{#if $$slots.header}
<slot name="header" slot="header" />
{/if}
Then you try to wrap it in a svelte:fragment, but it can't be in the #if either:
{#if $$slots.header}
<svelte:fragment>
<slot name="header" slot="header" />
<svelte:fragment>
{/if}
However, using the SlotFragment component works:
{#if $$slots.header}
<SlotFragment slot="header">
<slot name="header" />
<SlotFragment>
{/if}
Also ran into this issue. Conditional slots would be a very useful feature
I ran into this issue yesterday and spun up a repl to reproduce - https://svelte.dev/repl/b089c2c379e9404596445c16311bd1b9?version=3.50.1.
Jup, just ran into this as well. Would love to see this work as the suggested feature. Please add this, Svelte team! 😭💕
Please add this feature, it is deeply important for us to fully use the slot concept. I had to waive the slot feature and fully integrate the child component into the parent one, because of this, which goes against the concept of extracting logic into components.
Now I have to duplicate code in case I would need a similar child component in the future. Which unfortunately is bad practice.
In my case the if and each tag are generating the error.
Thanks
I add my support for the svelte team to add this feature. It's a common problem that currently needs very elaborate workarounds.
+1
+1
It has been more than 2 years that this feature request has been here, with quite a lot of community backing. Is there a timeline for it or is it even something planned to be implemented? I know that there's quite the push to get SvelteKit v1 out, but is there some hope at least of including this in Svelte at any point in the not too distant future @Conduitry @dummdidumm @benmccann ?
I'm just another guy who ran into this issue. Please fix it.
+1
Please don't spam all subscribers to this issue with +1 or the equivelant
Please don't spam all subscribers to this issue with +1.
I don't think this is spamming. It's upvoting, as it's a feature we really really need :)
It is spamming. Please use thumbs up to upvote the issue. I will be hiding your comment as it just adds noise and doesn't help figure out how to implement this
<div hidden={yourCondition} slot="slotName">hide if yourCondition is true else show</div>
This is only working with standard HTML-Elements out of the box. If the child is a custom Component, you could wrap it in a div or modify it to accept a hidden parameter.
The mentioned example would look like this:
<MyComponent> <a hidden={something()} slot="right-container">Hi</a> </MyComponent>
🙃
This limitation is particularly annoying when using transitions, since the simple workaround is to hide the element when the slot shouldn't be rendered, rather than removing it from the DOM entirely. Could a key
block work for this?
At the very least add an error message or something. I have just been debugging for two hours questioning everything I knew about Svelte bindings because I was trying to conditionally insert a component into a slot.
For people who are in a similar situation. You can wrap you component in a div and assign the slot there. So while this unfortunately currently doesn't work:
{#if errorVisibility}
<ErrorMessage slot="errorMessage" value="Incorrect username or password" />
{/if}
This does:
<div slot="errorMessage">
{#if errorVisibility}
<ErrorMessage value="Incorrect username or password" />
{/if}
</div>
As you'll probably reckon it is a band-aid solution because empty divs are far from ideal.
@uranderu thanks for that tip, I just came across this issue when trying to do the same. This solution does however not work with Fallback in the slots since $$slots.NAME will be true.
So far I've been super impressed with Svelte since its amazing, this is the first trouble I run into tbh.. Conditional slots Would be amazing
As a work around for making Fallbacks work I added an else to pass In the EM , But id rather have the em in the child comp tbh..
<div slot="content">
{#if post.content !== undefined}
<textarea>{post.content}</textarea>
{:else}
<em>No post content was found</em>
{/if}
</div>
For those who are running into this issue and require the element to actually be removed from the DOM rather than just hidden with CSS or wrapped in a slotted parent element, I came up with this action as a workaround.
function hideOrRemove({
node,
parent,
nextSibling,
shouldHide,
}: {
node: HTMLElement;
parent: HTMLElement | null;
nextSibling: ChildNode | null;
shouldHide: boolean;
}) {
if (shouldHide) {
node.remove();
return;
}
if (parent?.contains(nextSibling)) {
parent.insertBefore(node, nextSibling);
return;
}
parent?.appendChild(node);
}
export function hideElement(node: HTMLElement, condition: boolean) {
const nodeParent = node.parentElement;
const nodeNextSibling = node.nextSibling;
hideOrRemove({
node,
parent: nodeParent,
nextSibling: nodeNextSibling,
shouldHide: condition,
});
return {
update(newCondition: boolean) {
hideOrRemove({
node,
parent: nodeParent,
nextSibling: nodeNextSibling,
shouldHide: newCondition,
});
},
};
}
Which you can then use like so:
<div slot="header" use:hideElement={$shouldShowHeader} />
I would caution to consider this a dangerous approach and to use this at your own risk, as I've only used this for one specific use case, and have not given it much testing or investigation into how it might interact with svelte internals.
This requires ugly hacks to work around when using slot forwarding to child components. Its a greatly needed feature.
A feature with this level of importance should have given more attention than this IMHO.
While this issue still exists, I do have a workaround to propose. Conditionnal slots work fine with default slots, but not with named ones. What I do is just pass an extra prop to the components declaring the named slot that will enable/disable its display from within. It's not as elegant, but it works fine. Here's a REPL representing the use case : https://svelte.dev/repl/dda911c0804c43bd8d6d035ed0660e22?version=3.58.0
This feature is required. My use case is:
I am making a game, and level has a tutorial with pause / overlay / help messages. One of messages must be in place of game element (score board) to explain it.
My solution is to create Tutorial component, which renders Level component, and to wrap elements from level in slots with fallbacks, and providing tutorial messages as content for this slots.
But there is a problem, I want at some point to see element from a game (fallback content), not a message from a tutorial, so I guess if
-slot content or null
in slot content will be sufficient to show a fallback, but it isn't.
My current solution to add extra prop with visibility flags, and show fallback if flag is true, and slot if flag is false. It is not a declarative way to solve this problem, sadly.
For anyone having a hard time following up here:
This may be fixed by https://github.com/sveltejs/svelte/pull/8304 as mentioned above but as Svelte 5 changes a lot of stuff, they are waiting with merging it.
For anyone having a hard time following up here:
This may be fixed by #8304 as mentioned above but as Svelte 5 changes a lot of stuff, they are waiting with merging it.
That is very good news indeed. Any info if this will also address the related issue that a
Also, has anyone any information what is going on with #8535? Dynamic slot names are also sorely missing. If all three of these issues were addressed when Svelte5 releases, I would finally be able to do this:
<svelte:component this={importedComponent} {...componentProps}>
{#if componentSlots && componentSlots.length}
{#each componentSlots as compSlot}
<svelte:fragment slot={compSlot.name}>
{#if compSlot.currentContent.type === 'text' || (compSlot.currentContent.type === 'html' && !compSlot.currentContent.tag)}
{@html compSlot.currentContent.content}
{:else if compSlot.currentContent.type === 'html' && compSlot.currentContent.tag}
<svelte:element this={compSlot.currentContent.tag}>
{@html compSlot.currentContent.content}
</svelte:element>
{:else if compSlot.currentContent.type === 'component'}
<svelte:component this={compSlot.currentContent.content} {...compSlot.currentContent.props} />
{/if}
</svelte:fragment>
{/each}
{/if}
</svelte:component>
This will be more ergonomic in Svelte 5 using the new snippets feature: preview playground link. Slots will be deprecated, as such this feature won't be implemented in slots, but as shown in the preview playground it's easily achievable using snippets.
Hi,
I ended up not checking if the $$slots.header
is true, and moved the logic to a prop like hasHeader
.
Demo.svelte
export hasHeader: boolean = false;
{#if hasHeader} <------- instead of $$slot.header
<header>
<slot name="header" />
</header>
{/if}
This means that when you have something like this:
<Demo hasHeader={condition}>
<svelte:fragment slot="header">
{#if condition}
<p>HELLO</p>
{/if}
</svelte:fragment>
</Demo>
Hope it helps
@dummdidumm Is there any outlook of whether this syntax will end up being supported?
It's cool that snippets enable it to be achieved via props, but being able to handle it inside the component body would be nice as well.
+1
I'm adding here my workaround, in case anybody find it useful
I'm trying to conditionally forward a slot (meaning, if the slot hasn't been specified, I don't want to forward any slot at all) But as you already know
{#if $$slots.named_slot}....
<slot slot="named_slot" name="named_slot />
it will ALWAYS pass a slot, even if it hasn't been specifiedthe work around I found (ugly in deed but it seems to work and to be general enough) is to allow to receive a slots
prop to override the child's $$slot variable, like this:
like this:
<!-- Title.svelte -->
<script>
export let slots = $$slots // allow to override $$slots
</script>
<div>
{#if slots.title}
<h3><slot name="title" /></h3>
{/if}
<slot />
</div>
And this is how I use it to define an Input.svelte
component that may optionally receive a title slot that I want to forward to Title.svelte
<!-- Title.svelte -->
<script>
import Title from './Title.svelte'
export let name = ''
</script>
<!-- override $$slots -->
<Title slots={$$slots}>
<slot slot="title" name="title" />
<input {name} placeholder={name} />
</Title>
In this case the name of the slot (title
) is the same in the child (Title) and parent (Input) component, if they differ we could map them like this:
<!-- if the slot name in the child component is not the same as the parent, I can map them like this: -->
<Title slots={{child_slot: $$slots.parent_slot}}>
It's clunky, but I hope this one gets merged soon so I can get rid of this ugly workaround
here's a working repl: https://svelte.dev/repl/3c82d89f3b564bce82760aba3f5c9b44?version=4.2.12
Based on the closing of #6059 and #8304, this issue should be closed as well, since the Svelte team has already decided not to move forwarded with adding this or any other feature to slots since they will be deprecated in favor of snippets, which provide this functionality and so much more.
Is your feature request related to a problem? Please describe.
When I do something like the below, I get an error of:
Describe the solution you'd like I want to be able to do the first example and wrap my optional slot's in if statements. The reason for this is I actually have default slot text in my component that I want to show.
Describe alternatives you've considered The alternatives is doing something like this which has a lot of duplicate code.
How important is this feature to you? This is a big hassle for me and it would make for a lot cleaner code if I could wrap this slots in if statements. However, it would not affect my ability to code and use svelte.