Search code examples
vuejs3vue-componentastrojs

Vue + Astro: Is it posible for astro pages to get data from scoped slots of vue component?


Vue allows child components to pass data to parent components using scoped slots this way:

//child.vue

<template>
  <slot :msg="'pass me up!'">default message</slot>
</template>

//parent.vue

<template>
  <Child v-slot="{ msg }">{{ msg }}</Child>
</template>

And astro has its own version which is:

---
//Child.astro
const html = await Astro.slots.render('default', [Astro.props.msg.toUpperCase()]);
---
<Fragment set:html={html} />

---
//Parent.astro
---
<Child>{ msg => <span>{msg}</span> }</Child>

Is there a way to make Astro access vue scoped slots? Like the following? (which does not work btw)

//child.vue

<template>
  <slot :msg="'message from vue!'"></slot>
</template>

---
//Parent.astro
---
<Child>
  { t => <span>{t}</span> }
</Child>

Please ignore the fact that the imports and other boilerplate is ignored for these examples

UPDATE

i found a workaround (but naturally, it's not ideal)

//child.vue

<template>
  <template v-if="renderer">
    <span v-slot="renderer('message from vue!')"></span>
  </template>
  <template v-else>
    <slot v-else :msg="'message from vue!'"></slot>
  </template>
</template>

---
//Parent.astro
---
<Child renderer={ (t : string) => `<span>${t}</span>` }></Child>

i wrote this here and not as an answer because i believe there should be a better proper answer, better than mine


Solution

  • Since i could not find any other answer, this is my best try:

    //child.vue
    
    <template>
      <template v-if="renderer">
        <span v-html="renderer('message from vue!')"></span>
      </template>
      <template v-else>
        <slot v-else :msg="'message from vue!'"></slot>
      </template>
    </template>
    
    ---
    //Parent.astro
    ---
    <Child renderer={ (t : string) => `<span>${t}</span>` }/>