docs icon indicating copy to clipboard operation
docs copied to clipboard

`Astro.slots` example is not working

Open jcha0713 opened this issue 2 years ago • 6 comments

The example code for Astro.slots doesn't seem to work, and I'm not sure whether the given example is wrong or the api has a bug.

The code I tested is:

---
// components/Message.astro

let html: string = '';
if (Astro.slots.has('default')) {
  html = await Astro.slots.render('default', Astro.props.messages)
}
---
<Fragment set:html={html} />
---
// pages/index.astro

import Message from '../components/Message.astro'
---
<div>
  <Message messages={['Hello', 'world!']}>{(messages) => messages.join(' ')}</Message>
</div>

<!-- 
must be renders as
<div>Hello world!</div>
-->

This example gives me an error that says message.join is not a function. If I have made any mistake, please let me know. Thank you!

link to the doc: https://docs.astro.build/en/reference/api-reference/#astroslots minimal reproduction: https://codesandbox.io/s/distracted-shamir-hpxuel?file=/src/pages/index.astro

jcha0713 avatar May 17 '22 20:05 jcha0713

I'm confirming the behaviour in the CodeSandbox. I'm also getting messages.join is not a function

Furthermore, when I play around with variations of this, I'm getting messages is not defined, so I think the error is less about not being able to perform the join, and more about messages itself being undefined (and THAT's why messages.join is not a function.)

sarah11918 avatar May 17 '22 22:05 sarah11918

@aFuzzyBear I think you were going to take a look at this one?

sarah11918 avatar May 20 '22 14:05 sarah11918

Raising an issue on the main Astro repo for this as it is likely a bug. Here’s a Stackblitz reproduction:

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

We should remove this example from the docs in the meantime.

delucis avatar Jun 08 '22 21:06 delucis

Example in the docs has been commented out. When https://github.com/withastro/astro/issues/3562 is fixed, we can go back and revive the example.

Untill then, labelled as "on hold."

sarah11918 avatar Jun 16 '22 13:06 sarah11918

Hello! An update on this, the function works as expected, however the second argument of Astro.render.slots is an array of argument to pass, as such when trying to pass an array as a single parameter, it needs to be an item of the array:

So in this case, it needs to be the following:

html = await Astro.slots.render('default', [Astro.props.messages])

(Note the square brackets around Astro.props.messages!)

Otherwise, every item of the array will be passed as a separate argument, that you'd use like so:

<Component>
  {(hello, world) => <div>{hello}, {world}!</div>}
</Component>

Princesseuh avatar Aug 24 '22 14:08 Princesseuh

Waiting on this issue, then will document as a use case for Astro.slots.render in the reference docs.

There's a bit of an API design rough edge here. Normally, you'd only need to use Astro.slots.render for dynamically rendering a slot. But now it's the only way to implement "slot props" in Astro. So even though you're certain you want to render a specific slot, you're now forced to use Fragment and Astro.slots.render for that use case.

It's also a hidden feature, and doesn't match any existing slots implementation.

Vue: Scoped slots Svelte: Slot props

I think Svelte's implementation on the component definition side would be a great alternative to Astro.slots.render here.

<div>
    <slot foo="hello" bar="word"/>
</div>

On the consuming side, I like our current "function children" interface because it matches Astro's "JSX-like" design.

Jutanium avatar Aug 25 '22 16:08 Jutanium