fusionneoscmsafxvuejs-slots

Is it possible to define slots in neos fusion afx like you can in Vue?


In Vue.js I can define named slots for my components, besides my default slot:

<article>
  <header>
    <slot name="header">
      <h2>Default heading</h2>
    </slot>
  </header>
  <slot/>
</article>

and then use it like this:

<template>
  <FooArticle v-for="item in items">
    <template #heading>
      <h3>{{item}} Heading</h3>
    </template>
    <p>Just content</p>
  </FooArticle>
</template>

<script>
export default {
  name: 'App',
  components: {
    FooArticle
  },
  data() {
    return {
      items: ['First', 'Second']
    }
  }
}
</script>

Is this possible with Neos Fusion, to create a mechanism like this?


Solution

  • Yes this is possible, as you can use the @path decorator to overwrite a property of the wrapper element.

    First you define your props and then output them in the renderer.

    prototype(Foo.Components:Article) < prototype(Neos.Fusion:Component) {
    
        heading = afx`<h2>Default heading</h2>`
    
        content = ''
    
        renderer = afx`
            <article>
                <header>
                    {props.heading}
                </header>
                {props.content}
            </article>
        `
    }
    

    Then you want to override these "slots" (props) from the outside with the @path decorator. The whole element the decorator is defined on will override the specified prop "heading" of the wrapping element.

    prototype(Foo.Site:Home) < prototype(Neos.Fusion:Component) {
        items = ${['First', 'Second']}
    
        renderer = afx`
            <Neos.Fusion:Loop items={props.items}>
                <Foo.Components:Article>
                    <Neos.Fusion:Fragment @path="heading">
                        <h3>{item} heading</h3>
                    </Neos.Fusion:Fragment>
                    <p>just some content</p>
                </Foo.Components:Article>
            </Neos.Fusion:Loop>
        `
    }
    

    FYI, we use a Neos.Fusion:Fragment object to define the path decorator, so the fragment does not render any additional markup like an enclosing <div>. In this simple case, where we only want to render a single element into the slot, we could have omitted the fragment and just set the @path="heading" directly to the <h3>.