Skip to content

Conditionally pass child snippet as propΒ #15746

@rChaoz

Description

@rChaoz

Describe the problem

Any snippet declared under a component is automatically passed as a prop. This is great when this is what you want, but that's not always the case. There are 2 main issues with this:

  1. When the tree is mostly components, you are forced to put all helper snippets at the root level, which is not ideal (no sorting, scoping breaks, becomes cluttered)
  2. It is difficult & a bit boilerplate-y (also the same issue as above) to pass a snippet conditionally

As an example for (1), consider this tree:

<A>
  <B>
    <C>
      <AlternateList {data}>
        {#snippet itemEven(data)}
          <img class="even-styles" src={data.url} alt={data.alt} />
        {/snippet}
        {#snippet itemOdd(data)}
          <img class="odd-styles" src={data.url} alt={data.alt} />
        {/snippet}
      </AlternateList>
    </C>
  </B>
</A>

Now, suppose you want to extract the common list item to a snippet. Ideally, you'd place this snippet right above itemEven and itemOdd, but this is not possible, as it will become a prop. Since this tree is all components, you have no other choice than to place it at the root level:

{#snippet commonItem(class, data)}
  <img {class} src={data.url} alt={data.alt} />
{/snippet}

<A>
  <B>
    <C>
      <AlternateList {data}>
        {#snippet itemEven(data)}
          {@render commonItem("even-styles", data)}
        {/snippet}
        {#snippet itemOdd(data)}
          {@render commonItem("even-styles", data)}
        {/snippet}
      </AlternateList>
    </C>
  </B>
</A>

The more complex the component, the more root-level snippets you'll need, which becomes hard to keep track of. Additionally, snippet scoping, a great feature, breaks: a snippet only meant for use in AlternateList now pollutes the entire file and can potentially be missused.

For (2), consider this:

<Wrapper>
  <AppBar>
    {#snippet toolbar()}
      ...content...
    {/snippet}
    {#snippet headline()}
      ...more content...
    {/headline}
  </AppBar>
</Wrapper>

If you want to conditionally display the headline, this is the solution:

{#snippet headline()}
  ...more content...
{/headline}

<Wrapper>
  <AppBar headline={condition ? headline : undefined}>
    {#snippet toolbar()}
      ...content...
    {/snippet}
  </AppBar>
</Wrapper>

This feels a bit boilerplate-y when done multiple times, and not very idiomatic (if snippet is passed as prop, why is it not right under the receiving component?). It also breaks the scoping of the code, just like in the earlier example; content that exclusively belongs to the AppBar is now globally present.

Describe the proposed solution

Provide a way control how snippets automatically become props. This should not restrict the scope of the snippet, and fix issues (1) and (2) above. At first sight I feel like borrowing the syntax for keyed each is a decent starting point:

<AppBar>
  {#snippet helper() (false)}
    this is not passed as a prop
  {/snippet}

  {#snippet toolbar()}
    <!-- but can be used here -->
    {@render helper()}
  {/snippet}

  {#snippet headline() (condition)}
    <!-- the {#if headline}...{/if} in the AppBar correctly applies depending on condition -->
    ...content...
  {/snippet}
</AppBar>

...but of course, the actual syntax/approach here should be decided by the core maintainers.

Importance

would make my life easier

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions