Is your feature request related to a problem? Please describe.
I want to be able to add classes to slots so that i can style them directly.
Describe the solution you'd like
App.svelte
<MyComponent>
<ul slot="list">
...
</ul>
</MyComponent>
MyComponent.svelte
<slot name="list" class="my-list-style">
<p>No items found</p>
</slot>
Describe alternatives you've considered
This alternative works, but i still can't style the ul in my example correctly and it feels like it renders the fallback slot functionality useless.
{#if list.length}
<div class="my-list-style">
<slot name="list" />
</div>
{:else}
<p>No items found</p>
{/if}
How important is this feature to you?
There are work arounds, but nothing clean. I just feel like this should be functionality that should be part of the slot feature.
@tiddle The current way to achieve this is with let:class to expose the variable to be used on your element like this:
<MyComponent>
<ul slot="list" let:class={className} class={className}>
...
</ul>
</MyComponent>
I think this limitation makes sense because the component doesn't know anything about the child slots. It's up to the component user to figure out what to do with the slot props.
@jesseskinner I think you don't understand the OP's problem. Just like mine, I don't know what child component will be passed. Regardless of the passed child component inserted into the slot, I need to style it. E.g. I can't add special props and keywords to every single component I have and will ever create for this to work.
@GitGangGuy Sure, you want to be able to control the element used for the slot from the parent. Right now the syntax I used above is valid, where slot props become available through the let: directive on the slot element.
My concern is that this new feature would not be backwards compatible, because it would break my example code above. Would class become a special case, where it interprets it as an attribute to be used on the slot element instead of a prop? What about style? id? data-* attributes? I think instead, there would need to be some special way to make the distinction of what is a slot attribute and what is a slot prop to be consumed with let:. Maybe a new directive like <slot attr:class="abc"/>?
@jesseskinner I understand your concerns and I don't have a solution, but another use case for passing attributes through, would be transitions. Currently, you can't do <slot in:fade>
@tiddle True.. actually maybe that could be a constraint of the new feature, that only directives get passed down to the slot element. That'd work for class too: instead of class="foo" you could use class:foo={true} and have that passed through. That would get around my concerns of ambiguity, I think?
Named slots do currently always have a single root element, but this is a limitation of the current syntax and not a design feature. (Default slots, by contrast, already do not necessarily have a single root element.) We don't want to rely on there being a single root element - or prevent ourselves from ever implementing named slots without a single root node - and so there's not anything to apply the class to or the transition to.
It wasn't popular when treating class specially was nixed in #2870/#2888 and I don't expect it will be popular now either, but I think the core Svelte team really does feel strongly about this. Providing a blessed way to nicely use CSS variables like in this RFC is probably going to be the recommended way forward - or, alternatively, to use partially :global() selectors as an escape hatch to style descendant elements.
@Conduitry I don’t think that the possibility of multiple root elements is a problem here. In my case, if there are multiple root elements, I would like to apply the class to all those root elements with which the<slot> is replaced.
Currently, I can only do this with some ugly JS, by wrapping the <slot> in a div and then selecting all direct children of that div (div>*).
But this fix/solution also makes me face a problem: The <div> partially destroys the layout/design compared to when not using that div wrapper.
I hope we can continue implementing this feature again.
Syntax-wise, I would like to be able to pass id, style and class DOM attributes as well as (ideally) svelte props to whatever the slot was replaced with, so prefixing everything with attr in the slot that should be passed sounds like a good idea.
Examples: <slot attr:class=“test” attr:class:active={true} /> or <slot attr:style=“color: red” attr:id=“henlo” />
Instead of using a class one can also use the css attribute selector with the slot name in combination with the :global() modifier.
Example:
<MyComponent>
<p slot="mySlot">world</p>
</MyComponent>
MyComponent.svelte
<div>
Hello
<slot name="mySlot" />
</div>
<style>
:global( [slot="mySlot"] ) { ... }
</style>
This makes the additional wrapper around the slot obsolete
Most helpful comment
@Conduitry I don’t think that the possibility of multiple root elements is a problem here. In my case, if there are multiple root elements, I would like to apply the class to all those root elements with which the
<slot>is replaced.Currently, I can only do this with some ugly JS, by wrapping the
<slot>in a div and then selecting all direct children of that div (div>*).But this fix/solution also makes me face a problem: The
<div>partially destroys the layout/design compared to when not using that div wrapper.I hope we can continue implementing this feature again.
Syntax-wise, I would like to be able to pass
id,styleandclassDOM attributes as well as (ideally) svelte props to whatever theslotwas replaced with, so prefixing everything withattrin the slot that should be passed sounds like a good idea.Examples:
<slot attr:class=“test” attr:class:active={true} />or<slot attr:style=“color: red” attr:id=“henlo” />