sveltejs / rfcs

RFCs for changes to Svelte
274 stars 81 forks source link

Slot Attributes #15

Closed lukeed closed 10 months ago

lukeed commented 4 years ago

Rendered

RedHatter commented 4 years ago

Would sveltejs/svelte#2106 solve this? Something like

<div class="card">
  {#if $$slots.header}
    <div class="card-header">
      <slot name="header"/>
    </div>
  {/if}

  {#if $$slots.default}
    <div class="card-body">
      <slot />
    </div>
  {/if}

  {#if $$slots.footer}
    <div class="card-footer">
      <slot name="footer"/>
    </div>
  {/if}
</div>
lukeed commented 4 years ago

Being able to detect slot existence would, yes, but IIRC there was hesitation around this – I think due to implementation hurdles? Can't really remember the details

Conduitry commented 4 years ago

I don't think there are implementation hurdles - this is already sort of available as $$props.$$slots but there's no official public API for it currently. This is also discussed in https://github.com/sveltejs/svelte/issues/2106

lukeed commented 4 years ago

Thanks, missed the part where $$props.$$slots is already available.

So then here's what I have so far: https://svelte.dev/repl/69ca92e3995540a4a0a1865e6fc6b957?version=3.16.7

Then this RFC basically serves as a consolidation for the above while also adding ability to add additional props/attributes to each slot (https://github.com/sveltejs/svelte/issues/2106#issuecomment-518065422)


In the process, we'd hopefully be able to remove the whitespace-only trigger for <slot (default) /> (shown in REPL) but that may be a separate task.

Zizico2 commented 3 years ago

Sorry if I misread the RFC but there is stuff I'm sceptical about.

What happens when a slot doesn't have a unique child?

Will all top level children get assigned the attributes? Could we wrap the contents of the slot in a <div style="display: contents"></div> and apply the attributes to that?

I wrote an RFC (Declarative Actions) where I mentioned adding a <target /> component that behaves like your <slot /> extension, except it would only allow one child (as it was meant for actions, which can only be applied to one element at a time).

What happens when the attributes specified in the <slot /> aren't compatible with the elements inside it? Should Svelte not compile (seems too harsh xd)? Should there just be a warning? Should Svelte just clean up the invalid HTML for you and not tell you about it? What if the child is a Svelte Component and not an HTML Element? Svelte Components aren't compatible with most HTML attributes, would it apply the attributes to the component's top element?

One solution could be to (I'm gonna use <target /> insted of <slot /> as I feel it is different enough to warrant a new Element) have extra attributes on <target /> to allow you to specify allowed children.

Something like:

<!-- Card.svelte -->
<div class="card">
    <target allow="div" />
</div>

Would only allow a single div as a child. If you used this component and gave it a button it would not compile.

And something like:

<!-- Card.svelte -->
<div class="card">
    <target allow="div"  type="text"/>
</div>

Wouldn't compile right off the bat since a div shouldn't be assigned the attribute type.

You could even do:

<!-- Card.svelte -->
<div class="card">
    <target allow="div, button, form" />
</div>

This would allow one of those Elements as the root element and Svelte would be smart enough to allow the interception of their attributes list.

If you want to allow all don't include the allow attribute. If you want to allow all except some there could be a deny attribute.

As in:

<!-- Card.svelte -->
<div class="card">
    <target deny="svg" />
</div>

And, again, Svelte would be smart enough too allow you to use the right attributes.

You could even allow/deny specific Svelte Components (which could be useful for design systems) or only allow or only deny all Svelte Components:

Ex 1:

<!-- Card.svelte -->
<div class="card">
    <target deny="SvelteComponent" />
</div>

This would deny any Svelte Component and would mean roughly the same as:

<!-- Card.svelte -->
<div class="card">
    <target allow="HTMLElement" />
</div>

Ex 2:

<!-- Card.svelte -->
<div class="card">
    <target allow="SomeRandomCustomSvelteComponent, SomeOtherRandomCustomSvelteCompoonent" />
</div>

This would only allow those 2 Svelte Components as children and, once more, Svelte could be able (this doesn't seem as black and white as HTMLElements since 2 Components having props with the same name doesn't mean they have the same semantics) to allow the props in common.

I can see this being written off as too convoluted but I think it's a decent way to go about the problem.

Other questions:

How would directives, specifically style directives work?

How would style properties work?

How would actions work?

How would Svelte scope styles since the slot's content would need access the class selectors in its parent, or any selector for that matter?

iacore commented 2 years ago

Slot variables is now available in Svelte, which is more general a solution than this proposal. Demo: https://svelte.dev/repl/7853ade2c8fa43dcbe4cb128cf272a79?version=3.44.3

lukaszpolowczyk commented 2 years ago

@lukeed It looks like your RFC has something in common with mine - https://github.com/sveltejs/rfcs/pull/68

Please check my RFC, and tell me if it covers 100% of your RFC?

dummdidumm commented 10 months ago

Snippets will replace slots (they are still around but deprecated) in Svelte 5 and have the capabilities that are wanted. The $$slots.x feature that was introduced a while ago also solves many of the presented cases. Therefore closing this RFC - thank you.