Skip to content

Conditionally pass child snippet as prop #15746

New issue

Have a question about this project? No Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “No Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? No Sign in to your account

Open
rChaoz opened this issue Apr 11, 2025 · 2 comments
Open

Conditionally pass child snippet as prop #15746

rChaoz opened this issue Apr 11, 2025 · 2 comments

Comments

@rChaoz
Copy link
Contributor

rChaoz commented Apr 11, 2025

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

@gterras
Copy link

gterras commented Apr 12, 2025

Just my thoughts as a user:

Examples 1 and 2 might be contrived but using snippets for styling purpose is usually overkill, here :nth-child(odd) and :nth-child(even) are more suited for this job.

Example 2 can't you have commonItem declared in AlternateList ?

Example 3 as per the docs snippets turned into props is an authoring convenience, when it stops to be convenient you can just switch back to regular syntax : <AppBar display_headline={condition}> or {#if headline}{@render headline()}

@Ocean-OS
Copy link
Contributor

You could also use createRawSnippet for some (if not all) of these cases.

No Sign up for free to join this conversation on GitHub. Already have an account? No Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants