Previously, components were single-tag components, such as
, but pages often needed to allow HTML elements and components to combine with each other to build complex pages

Components in Svelte also allow you to combine larger and stronger components by using components as containers and adding child components to them. This container is called Slots. This is very similar to what slots do in Vue.

The default slot

We know that HTML elements can have child nodes

<div>
  <p>The p element is a child of div</p>
</div>
Copy the code

Components in Svelte can also be used as containers to store content, but at the time of defining the component, you don’t know what content to put

So Svelte uses the slot tag for placeholder operations

Unlike Vue, Svelte allows multiple slots with the same name to be used together. For example, you can have multiple default slots in a child component.

However, only one value can be passed in, and all the corresponding slots will be updated

<! -- subcomponent -->
<div class="box">
  <! <slot></slot> or <slot /> This unnamed slot is called a default slot or a default slot and the value passed by the parent component is automatically replaced by the default slot by default if the parent component does not implement the slot content, If the slot has no default value, the position of the slot will not display any content.
  <slot></slot> 
</div>

<! --------------------------------->

<! -- parent component -->
<script>
  import Box from './Box.svelte';
</script>

<Box>
  <! -- Put content here -->
</Box>
Copy the code

Slot default content

The slot fallback can specify

elements. What should be displayed by default if the content is empty

<! -- subcomponent -->
<div class="box">
  <slot>
    <em>default value</em>
  </slot>
</div>

<! -- parent component -->
<Box>
  <p>Default content is not used</p>
</Box>

<! -- use the default content -->
<Box />
Copy the code

Named slot

While we have a default slot, we sometimes need more control over what we place. At this point you can use named slots

<! -- subcomponent contactCard.svelte -->
<style>
  .contact-card { width: 300px; border: 1px solid #aaa; padding: 1em; }
</style>

<article class="contact-card">
  <h3>
    <! -- Use the name attribute to name the component -->
    <slot name="name">Unknown name</slot>
  </h3>

  <div>
    <slot name="address">Unknown address</slot>
  </div>
</article>

<! --------------------------------------------------------->

<! -- parent component -->
<script>
  import ContactCard from './ContactCard.svelte';
</script>

<ContactCard>
  <! -- Use the slot attribute to specify which slot to use -->
  <span slot="name">P. Sherman</span>
  <span slot="address">42 Wallaby Way Sydney</span>
</ContactCard>
Copy the code
<! -- subcomponent -->
<article class="contact-card">
  <h3>
    <slot name="name">Unknown name</slot>
  </h3>

  <div>
    <slot name="address">Unknown address</slot>
  </div>

  <! In this case, the contents of both h3 slots will be replaced by P. Sherman -->
  <h3>
    <slot name="name">Unknown name</slot>
  </h3>
</article>

<! --------------------------------------------------------->

<! -- parent component -->
<script>
  import ContactCard from './ContactCard.svelte';
</script>

<ContactCard>
  <span slot="name">P. Sherman</span>

  <! -- but on the call side, can't provide two contents with slot 'name' -->
  <span slot="name">P. Sherman</span>

  <span slot="address">42 Wallaby Way Sydney</span>
</ContactCard>
Copy the code

Detecting slot contents

In some cases, you might want to control how parts of a component are displayed based on whether the parent component already provides the contents of a slot

In this case, you can use the variable $$slots specifically to check slots

$$slots is an object whose properties are the names of all slots passed in by the parent component.

If the parent component leaves the slot empty, $$Slots does not have the name of the slot.

<! -- subcomponent -->
<script>
  export let title = ' '
</script>

<article>
  <h2>{title}</h2>
  <hr />
  <div><slot name="content" /></div>
	
  <! The parent component passes a value to the comments slot -->
  {#if $$slots.comments}
  <div style="margin-top: 30px;">Comment on:<slot name="comments" />
  </div>
  {/if}

</article>

<! ----------------------------------------------->

<! -- parent component -->
<script>
  import Article from './Article.svelte'
</script>

<Article title="Test title">
  <div slot="content">Here's the test</div>
</Article>
Copy the code

Slot properties

The slot property can be used when the child component needs to pass the state back to the parent component for logical determination in the parent component

Subcomponents Hoverable. Svelte

<script>
  let hovering;

  function enter() {
    hovering = true;
  }

  function leave() {
    hovering = false;
  }
</script>

<div on:mouseenter={enter} on:mouseleave={leave}>
  <! -- Hovering properties will be passed to the elements that might implement the slot -->
  <slot {hovering} ></slot>
</div>
Copy the code

The parent component

<script>
   import Hoverable from './Hoverable.svelte';
</script>

<! -- The default slot uses the let keyword on the component for receiving versus let Hovering = hovering within the Hoverable component.
<Hoverable let:hovering>
  <div class:active={hovering}>
     {#if hovering}
        <p>I am being hovered upon.</p>
     {:else}
        <p>Hover over me!</p>
     {/if}
    </div>
</Hoverable>

<style>
  div {
   padding: 1em;
   margin: 0 0 1em 0;
   background-color: #eee;
  }

  .active {
    background-color: #ff3e00;
    color: white;
  }
</style>
Copy the code

Of course, for ease of use, we can also alias the state passed in by the child component upon receipt

<! -- Either Active or Let Active = Hovering --> within Hoverable components.
<Hoverable let:hovering={active}>
  <div class:active>
    {#if active}
       <p>I am being hovered upon.</p>
    {:else}
       <p>Hover over me!</p>
    {/if}
  </div>
</Hoverable>
Copy the code
<! -- subcomponent -->
<div on:mouseenter={enter} on:mouseleave={leave}>
   <slot {hovering} name='box'></slot>
</div>

<! -- parent component -->
<Hoverable >
  <! If the value of a named attribute is accepted, the value of a named attribute is accepted in a slot="..." Use let directives on elements of attributes, rather than on the component itself. -->
  <div slot="box" let:hovering>
    {#if hovering}
       <p>I am being hovered upon.</p>
    {:else}
       <p>Hover over me!</p>
    {/if}
  </div>
</Hoverable>
Copy the code

The slot properties on slot A are passed back to the parent component, and the state passed is scoped only within the usage scope of slot A.

Child components

<div on:mouseenter={enter} on:mouseleave={leave}>
   <slot {hovering} name='box'></slot>
   <slot>default slot value</slot>
</div>
Copy the code

The parent component

<Hoverable >
   <div slot="box" let:hovering>
     {#if hovering}
        <p>I am being hovered upon.</p>
     {:else}
        <p>Hover over me!</p>
     {/if}
   </div>

   <! The code below will report an error -->
   <div>
     {#if hovering}
        <p>I am being hovered upon.</p>
     {:else}
        <p>Hover over me!</p>
     {/if}
    </div>
</Hoverable>
Copy the code