In Svelte, I am using the Modal component.
This component provides the possibility do declare a div
with the property slot="footer"
.
This will keep the footer always at the bottom of the modal. It will make the body scroll if there is a lot of content, while keeping the footer visible anchored at the bottom of the modal.
My problem?
I'd like to be able to modify the content of this footer from a child component that I am using inside the Modal component. This child component has custom logic that will modify the footer content (not text, but html elements like buttons).
I tried to move the div <div slot="footer">
inside the child component but I got this error:
Element with a slot='...' attribute must be a child of a component or a descendant of a custom element
I also tried this solution but I did not managed to make it work. Not sure if I did an error or it's not really related to my case (I'm still a new with Svelte). It seems like that the "footer" option in the child component does NOT reach the parent component.
This is my code:
<script lang="ts">
import { Modal } from "flowbite-svelte";
import TestComponent from "./TestComponent.svelte";
</script>
Parent component:
<Modal open={true} size="lg" class="m-4">
<!-- Modal body -->
<div class="space-y-6 p-0"><p>BODY CONTENT</p></div>
<TestComponent />
<!-- Modal footer -->
<div slot="footer" class="flex w-full justify-end">
<p>FOOTER CONTENT</p>
</div>
</Modal>
<!-- Child component -->
<p>SOME TEXT THAT MUST BE CONFIRMED WITH A BUTTON IN THE MODAL</p>
<!-- show button A or B in parent component based on some logic -->
<!-- <div slot="footer" class="flex w-full justify-end"></div> - enabling triggers error -->
Is there a way to achieve this? Of course I am aware that I could move the logic in the footer directly, but I was trying to modularize the code.
Thanks in advance for any help!
Use events1 or bound properties to communicate between the child component and the parent. E.g.
<script>
let mode;
</script>
<Model>
...
<Child bind:mode />
<div slot="footer" class="flex w-full justify-end">
{#if mode == 'a'}
<!-- Button A here -->
{:else if mode == 'b'}
<!-- Button B here -->
{/if}
</div>
</Modal>
<!-- child -->
<script>
export let mode; // <- change this as needed
</script>
If the buttons should be extracted to their own component, you could pass the property down into said component.
For more indirect communication it is also possible to use a store in a context. For that to work and the same context being shared between relevant components, the context has to be set at a common ancestor in the component hierarchy, in this case e.g. the parent component containing the modal. Both the child and any components in the footer then can update and react to changes in the store.
1 In Svelte 5, events are done via callback functions as props rather than using createEventDispatcher
.