[SalesForce] Assign content to multiple slots in LWC: how to insert the same slot content to multiple template slots in LWC

I want to build a custom configurable interface to pass two buttons to header and footer of a standard card element.

So, I have a component card with card template

<template>
    <lightning-card  title={title}>
        <slot name="cancel" slot="actions"><lightning-button label="Cancel"></lightning-button></slot>
        <slot name="save" slot="actions"><lightning-button label="Save"></lightning-button></slot>

        Content

        <slot name="cancel" slot="footer"><lightning-button label="Cancel"></lightning-button></slot>
        <slot name="save" slot="footer"><lightning-button label="Save"></lightning-button></slot>

    </lightning-card>    
</template>

and another custom component customCard which uses this template

<template>
    <c-card>
        <lightning-button label="Cancel" title="Cancel" onclick={handleCancel} class="slds-m-left_x-small" 
            slot="cancel"></lightning-button>
        <lightning-button variant="success" label="Save" title="Save" onclick={handleSave} class="slds-m-left_x-small" 
            slot="save"></lightning-button>
    </c-card>
</template>

When I open card component, I see both buttons in the header and the footer
enter image description here

When I open customCard component, I see only buttons in the footer but not in the header
enter image description here

I have found that for example for another frameworks like vue.js it is possible to insert the same content into multiple slots using v-for

I tried to adopt this approach and define a property with slot list since I cannot set it directly

import { LightningElement } from 'lwc';

export default class Card extends LightningElement {
    slots = ['actions','footer'];
}

and then use template:forEach for LWC

    <template for:each={slots} for:item='slot'>
        <slot name="cancel" key={slot} slot={slot}><lightning-button label="Cancel"></lightning-button></slot>
    </template>
    <template for:each={slots} for:item='slot'>
        <slot name="save" key={slot} slot={slot}><lightning-button label="Save"></lightning-button></slot>
    </template>

however, when I try to deploy this code, it raises an exception

LWC1081: Slot attribute value can't be an expression.

Is there any way to work around this problem?


Update:
I didn't mention that I would like to process the data from properties stored in customCard on save click

So actually I have something like following

<template>
    <lightning-card  title={title}>
        <slot name="cancel" slot="actions"><lightning-button label="Cancel"></lightning-button></slot>
        <slot name="save" slot="actions"><lightning-button label="Save"></lightning-button></slot>

        <slot>Content</slot>

        <slot name="cancel" slot="footer"><lightning-button label="Cancel"></lightning-button></slot>
        <slot name="save" slot="footer"><lightning-button label="Save"></lightning-button></slot>

    </lightning-card>    
</template>

and custom component

<template>
    <c-card>
        <lightning-button label="Cancel" title="Cancel" onclick={handleCancel} class="slds-m-left_x-small" 
            slot="cancel"></lightning-button>
        <lightning-button variant="success" label="Save" title="Save" onclick={handleSave} class="slds-m-left_x-small" 
            slot="save"></lightning-button>
        <lightning:input value={data1}></lightning:input>
        <lightning:input value={data2}></lightning:input>
         ....
        <lightning:input value={data100}></lightning:input> 
    </c-card>
</template>

and in handleSave

handleSave() {
   process(data1);
   process(data2);
   ...
   process(data100);
}

Best Answer

So far I ended up with the following code in template component

<template>
    <lightning-card  title={title}>
        <!-- <template for:each={slots} for:item='slot'>
            <slot name="cancel" key={slot} slot={slot}><lightning-button label="Cancel"></lightning-button></slot>
        </template>
        <template for:each={slots} for:item='slot'>
            <slot name="save" key={slot} slot={slot}><lightning-button label="Save"></lightning-button></slot>
        </template>-->


        <slot name="cancel1" slot="actions"><lightning-button label="Cancel"></lightning-button></slot>
        <slot name="save1" slot="actions"><lightning-button label="Save"></lightning-button></slot>

        Content

        <slot name="cancel2" slot="footer"><lightning-button label="Cancel"></lightning-button></slot>
        <slot name="save2" slot="footer"><lightning-button label="Save"></lightning-button></slot>

    </lightning-card>    
</template>

and the following code in the custom component

<template>
    <c-card>
        <lightning-button label="Cancel" title="Cancel" onclick={handleCancel} class="slds-m-left_x-small" 
            slot="cancel1"></lightning-button>
        <lightning-button variant="success" label="Save" title="Save" onclick={handleSave} class="slds-m-left_x-small" 
            slot="save1"></lightning-button>

        <lightning-button label="Cancel" title="Cancel" onclick={handleCancel} class="slds-m-left_x-small" 
            slot="cancel2"></lightning-button>
        <lightning-button variant="success" label="Save" title="Save" onclick={handleSave} class="slds-m-left_x-small" 
            slot="save2"></lightning-button>
    </c-card>
</template>

however, I personally consider this code ugly and repetitive and I would opt for a better and cleaner solution if such solution exists.

enter image description here

Related Topic