Vue Slots.

Have you ever heard about composition over interitence?

Slots are basically compostion. It saves you from deep nesting of components inside another and trust me, it is fun.

Let me show you, how to do it.

If you are from React background and know about props.children, slots are exactly that in vue. See, learning a framework helped you to learn another.

Suppose you have a contact page in your website, where you want to add a form with some input fields and a number of buttons for resetting the form or sending the message. So, how will we do that. We will first make a button component and import that in form component to use it at multiple times and then will import form component into contact form. And then if you need to import that contact form into an another vue template? Umm, that sounds like too much nesting which would be very difficult to handle in the long run.

Let's see how will we do that with the help of slots.

Below is a vue component template FormButton which we will need inside the form component. Note that props are being used to get the data from parent component to child component and $emit vue event is used to pass the click event from child to parent. To know more about vue events, checkout the vue documentation.

FormButton

<template>
  <button 
    @click="buttonClicked()" 
    class="btn" 
    :class="{solid: solid, ghost: ghost}
  >
    {{name}}
  </button>
</template>

<script>
    export default {
        props:[ 'name', 'solid', 'ghost' ],
        methods:{
            buttonClicked(){
                this.$emit( 'btn-clicked' )
            }
        }
    }
</script>

<style>
    .ghost {
        border: 1px solid #ccc;
        background: transparent;
    }
    .solid {
        background: green;
        color: white;
    }
</style>

Below is the vue components of ContactForm and ContactUsPage templates. Note that we are importing the FormButton component inside theContactUsPage template and not inside the ContactForm template. The reason behind this is that we want to keep all our business logic in one main file which is here theContactUsPage and all the presentational code of the form element in a separate file which is the ContactForm template here. Now the question is, if we import the formbutton inside theContactUsPage template, how will ContactForm template access them? And the answer is vue SLOT.

ContactForm

<template>
  <form>
    <input type="text">
    <textarea></textarea>
    <slot></slot>
  </form>
</template>

ContactUsPage

<template>
    <div>
        <div>
            // navigation here
        </div>
        <header>Brand Name</header
        <contact-form>
            <form-button name="Reset" ghost="ghost" @btn-clicked="reset()"></form-button>
            <form-button name="Send" solid="solid" @btn-clicked="sendEmail()"></form-button>
        </contact-form>
    </div>
</template>
<script>
    import ContactForm from 'components/contactform.vue';
    import FormButton from 'components/formbutton.vue';
    export default {
        methods:{
            reset(){
               // reset the form
            },
            sendEmail(){
               // email sending code
            }
        },
        components: {
            contactForm: ContactForm,
            formButton: FormButton
        }
    }
</script>

So, Whatever is written inside the opening and the closing tag of the <contact-form> will be accessed using <slot></slot> tag inside the Form template. So, in place of <slot></slot> the reset and Send button will be seen in the browser. :)