Closed Fryuni closed 4 weeks 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.
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.
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>
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:
slot
or include a dash -
(like you would typically use for web components)// 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>
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?
@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!
@sarah11918 Ya, no problem, I can tackle this issue
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.
📚 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