rfcs icon indicating copy to clipboard operation
rfcs copied to clipboard

rules for slot attribute and let directive

Open tanhauhau opened this issue 4 years ago • 11 comments

Rendered

Related issues:

  • https://github.com/sveltejs/svelte/issues/3385

tanhauhau avatar Mar 01 '20 16:03 tanhauhau

Remind me where we're supposed to comment on RFCs? Here?

arxpoetica avatar Mar 02 '20 14:03 arxpoetica

@arxpoetica yup. free to comment it here. 👍

tanhauhau avatar Mar 02 '20 14:03 tanhauhau

Sorry for being late to the party, this had escaped my vigilance.

As I understand the RFC, this is mostly increasing stability by removing buggy edge cases, and adding more meaningful compiler errors. Of course, I'm all in favor of this.

There is just this point:

  1. No nesting of slot attribute:

Is there a hard technical reason for this? Like it is really too complicated to implement in a sane way...

Because I feel there could be some fun applications in userland wit slot nesting. Typically, when publishing components for other to use, I think there might be interesting patterns allowing to provide advanced default contents, and default contents of default contents, etc.

I think I'd prefer if it remained possible. Now, if the current implementation is already buggy, and it is hard to overcome, I understand it is the right move to disallow it clearly and pop an informative error message. At least for now...

And, more importantly, I want to say I can't wait to see something like this supported:

<Component>
  <svelte:slot let:a slot="foo">
    <OtherComponent>{a}</OtherComponent>
  </svelte:slot>
</Component>

I have no special attachment to the syntax ({slot foo} or `<Component slot="foo" /> would work equally well for me), but I think it would be a huge improvement if we can remove the limitation that requires to have an element with named slots (i.e. #1037).

It's the single feature I miss the most in Svelte currently. It would really eases things up for integration of third party libraries, where a precise element structure is often expected. And component publishers too. And, generally, it would open new perspectives for what we can do with slots. The upvotes in #1037 shows that I'm not alone in thinking this.

@tanhauhau Any chance supporting this is in your plans? As I understand it, your related PR would open the way for it?

Oh, and thanks a lot for all your bug smash and all. Removing all those pesty edge cases makes Svelte really better for all of us :heart:

rixo avatar Mar 15 '20 17:03 rixo

I think there might be interesting patterns allowing to provide advanced default contents

You can provide content for the default content https://svelte.dev/repl/0820cef07e3d4a41a4bccbb2040493f6?version=3.20.0

I still don't see a reason for having nested slot template, (element with slot="..." or <svelte:slot>)

Any chance supporting this is in your plans?

yes, with https://github.com/sveltejs/svelte/pull/4556, you should be able to write

<Component>
  <svelte:slot slot="foo">
      <div>hello</div>
      <div>world</div>
  </svelte:slot>
</Component>

<Component>
  <svelte:slot slot="foo">
      <OtherComponent />
  </svelte:slot>
</Component>

tanhauhau avatar Mar 16 '20 00:03 tanhauhau

Sorry for taking so long to come back at this...

So, you're right, your REPL is exactly what I had in mind, "content for the default content". I misread the RFC. And I also totally agree with your opinion and proposed solutions about nesting slots on the consumer side.

And yes, your 2nd example with OtherComponent is precisely what I was hoping for.

So... Thanks again! I hope the PR will land soon :)

rixo avatar Mar 25 '20 22:03 rixo

As we already have elements {@html .. } and {@debug} - may we use new {@slot...} tag instead <svelte:slot...>? As for me it may be more svelty and less boilerplate.

Instead <svelte:slot slot="foo"> we may use {@slot "foo"} or even better {@slot:foo} to avoid using expression as slot name.

Common examples will be look like this:

<Component>
   Content for default slot
</Component>

<Component>
  {@slot:foo}Content of named slot{/slot}
  Content for default slot
</Component>

<Component>
  {@slot:foo}
      <div>hello</div>
      <div>world</div>
  {/slot}
</Component>

<Component>
  {@slot:foo}<OtherComponent/>{/slot}
</Component>

<!-- let-derictive replacement -->
<Component>
  {@slot:foo a,b,c}
      <OtherComponent>A is {a}</OtherComponent>
      <OtherComponent>B is {b}</OtherComponent>
      <OtherComponent>C is {c}</OtherComponent>
  {/slot}
</Component>

<!-- they are same -->
<Component let:a>
  A is {a}
</Component>
<!-- and -->
<Component>
  {@slot a}A is {a}{/slot}
</Component>

AlexxNB avatar May 02 '20 20:05 AlexxNB

I personally prefer the syntax suggestion by @AlexxNB, but for consistency's sake we should probably use {#slot:foo} instead of {@slot:foo} if this syntax is adopted.

milkbump avatar May 23 '20 21:05 milkbump

The problem with using a custom syntax like {#slot} is that we lose the parallel that already exists with native (custom elements) <slot />, and where slot="name", like Svelte currently, also has to be assigned to an element (e.g. <div slot="name">).

Slots can already be pretty confusing to comprehend, I think it is better to stick to what people (may) already know.

In fact, even <svelte:slot /> feels a bit confusing because it introduces a new kind of slot, where the concept is already a bit crowded (there the <slot /> in the parent component, and the target slot="name" for the slot content).

Maybe something more neutral just meaning a virtual element / no-element container would better express the intention? And regarding the syntax, maybe it would also feel less repetitive / boilerplaty than <svelte:slot slot="name" />... Maybe something like <svelte:fragment slot="name"> or <svelte:virtual slot="name">?

rixo avatar May 23 '20 22:05 rixo

@rixo I agree with your first point about the presumed complexity of slots. But it's precisely because of your second point about the "boilerplate-y" nature of <svelte:slot slot="name" with "slot" used twice that I prefer {#slot:foo}.

That said, if we use the <svelte: tag syntax, I don't think using <svelte:virtual or <svelte:fragment agrees with your argument about slot complexity. I think <svelte:slot is much easier to understand and teach.

milkbump avatar May 23 '20 23:05 milkbump

The reason I am proposing <svelte:slot slot="foo"> over {#slot:foo} is that, it's more familiar to have let: attribute and possibly bind: (https://github.com/sveltejs/svelte/issues/3617) in future:

<svelte:slot slot="foo" let:a={b}>
</svelte:slot>

vs

{#slot:foo let:a=b} <-- not sure how to express attribute in a more familiar syntax
{/slot}

tanhauhau avatar May 26 '20 04:05 tanhauhau

quick thoughts:

  • definitely agree it needs to be something element-ish, i.e. <svelte:xxx>. Also agree that <svelte:slot> is perhaps a little confusing since it replaces the slot attribute rather than the slot element, so <svelte:fragment> would make more sense
  • I'd suggest that the rule shouldn't be against nesting slots specifically, but rather using slot="foo" anywhere other than as a direct child of a component should be considered invalid
  • That probably shouldn't apply to slots inside custom elements? Not 100% sure what the rules are there, but we should presumably stick to them
  • Basically agree with this whole RFC but since some aspects are technically breaking changes we will probably need to just warn loudly for now, and continue with the current behaviour if someone does nest slots or have duplicates or whatever. Unless we choose to use the semver ju-jitsu of calling the changes a bugfix

Rich-Harris avatar Jun 27 '20 14:06 Rich-Harris

Snippets will replace slots (they are still around but deprecated) in Svelte 5 and will remove the inconsistencies present with slots. Therefore closing this RFC - thank you.

dummdidumm avatar Nov 16 '23 16:11 dummdidumm