withastro / docs

Astro documentation
https://docs.astro.build/
MIT License
1.33k stars 1.48k forks source link

Document passing information from a component to a function slot #8855

Closed Fryuni closed 4 weeks ago

Fryuni commented 3 months ago

📚 Subject area/topic

Slots

📋 Suggested page

https://docs.astro.build/en/basics/astro-components/#slots

📋 General description or bullet points (if proposing new content)

🖥️ Reproduction of code samples in StackBlitz

https://stackblitz.com/edit/github-oqp5kf?file=src%2Fcomponents%2FMyList.astro,src%2Fpages%2Findex.astro

Soviut commented 3 months ago

I originally asked about this because I use Vue's "scoped slots" a lot. https://vuejs.org/guide/components/slots.html#scoped-slots

It would be great if this pattern was given its own sub-section and named "Scoped slots". While the approach from Vue is very different, it would at least convey the intent.

Soviut commented 3 months ago

For context, here's what I was demonstrating with Vue in the Discord

in the long term what i'm hoping for is this (note: Vue syntax)

MyList.vue (component)

<script setup lang="ts">
defineProps<{
  items: string[]
}>()
</script>

<template>
  <ul>
    <li v-for="(item, index) in items">
      <slot :item="item" :index="index" :total="items.length" />
    </li>
  </ul>
</template>

Index.vue (usage)

<MyList :items="items" v-slot="{ item, index, total }">
  <div>
    {{item}}
    <span>( {{index}} / {{total}} )</span>
  </div>
</MyList>

Note how the v-slot yields not only the item but also additional context like the index and total from within the component.

Here is a slightly modified Stackblitz that @Fryuni sent to me that does the same thing in Astro https://stackblitz.com/edit/github-oqp5kf-ozddjd?file=src%2Fcomponents%2FMyList.astro,src%2Fpages%2Findex.astro

---
const { items } = Astro.props;
---
<ul>
  {items.map((item, index, list) => (
    <li set:html={Astro.slots.render('default', [item, index, list])} />
  ))}
</ul>
<MyList items={numbers}>
  {(item, index, list) => (
    <>
      Item {index}:
      <ul>
        <li>Value: {item}</li>
        <li>Last occurrence: {list.lastIndexOf(item)}</li>
      </ul>
    </>
  )}
</MyList>

While I prefer the Vue syntax, this makes it clear that scoped slots are possible.

sarah11918 commented 3 months ago

Thanks for creating this issue! Is @BryceRussell 's comment on Discord relevant to capture here, too? https://discord.com/channels/830184174198718474/872579324446928896/1263701298591698954

When passing functions to named slots, does not work, it has to be a html tag that does not contain a - like: , or , etc

<YourAstroComponent>
  <fragment slot="with-options">
    {() => ...}
  </fragment>
</YourAstroComponent>

Issue: https://github.com/withastro/astro/issues/6683

BryceRussell commented 3 months ago

I think it would be great to document named slot functions, but it will be tricky.

The default assumption user's have when passing named slot functions is to use a <Fragment>:

<Component>
    <Fragment slot="one">
        {() => ...}
    </Fragment>
</Component>

But due to the way Astro renders components/slots this is not possible. Instead, users have to use a HTML tag to pass the function to a slot:

<Component>
    <fragment slot="one">
        {() => ...}
    </fragment>
</Component>

But this syntax some issues because it feels hacky:

// These example do the same thing but the last 3 examples are less explicit and more confusing than the first

<Component>
    <fragment slot="one">
        {() => ...}
    </fragment>
</Component>

<Component>
    <f slot="one">
        {() => ...}
    </f>
</Component>

<Component>
    <one slot="one">
        {() => ...}
    </one>
</Component>

<Component>
    <div slot="one">
        {() => ...}
    </div>
</Component>
sarah11918 commented 3 months ago

Thanks Bryce! While maybe not "quick" to document, you've laid out the pattern very well in a way that makes sense and I do think we could get that into docs.

@Soviut if you had seen documentation like Bryce's post above, would that have answered your original question, and would you have been able to work from that?

sarah11918 commented 2 months ago

@BryceRussell would you be willing to make an attempt to put a PR together for docs based on what you added above?

I will add this to the list of improvements I think we should totally make!

BryceRussell commented 2 months ago

@sarah11918 Ya, no problem, I can tackle this issue

sarah11918 commented 4 weeks ago

closing this as partially addressed by 8946, and i think good for now for what we want to call attention to as happy path behavior.