How To Build A Reusable Vuejs Modal Component

July 29, 2019 (5y ago)

If you prefer to watch a video, you can watch it over here  - https://youtu.be/L9-KlbESFTQ

Modal is one of the essential components in the user interface. It's good to display or receive a response from the user without moving to other pages. I'm going to build a Modal component and reusable in every page.

Modal that we're going to build is a simple modal with static content inside it.

Create a VueJS component

Create a new file in your Vue apps and define them as Vue components. Set the component name in the script section.

Modal.vue

<script>
export default {
  name: "Modal",
};
</script>

I'll be using TailwindCSS to style the components.

Let me know if you need any tutorial/guide on building UI with TailwindCSS.

Modal.vue

<template>
  <div class="modal">
    <div class="container">
      <div class="modal__title">Direction</div>
      <p>Get a direction with your favourite apps</p>
      <a href="#" class="btn gmaps">
        <img src="https://img.icons8.com/color/420/google-maps.png" /> Google
        Maps
      </a>
      <a href="#" class="btn waze">
        <img src="https://img.icons8.com/color/420/waze.png" /> Waze
      </a>
      <button class="mt-3 border-b border-teal font-semibold">Close</button>
    </div>
  </div>
</template>
 
<script>
export default {
  name: "Modal",
};
</script>
 
<style lang="css" scoped>
.modal {
  background-color: rgba(0, 0, 0, 0.7);
}
</style>

_how-to-build-a-reusable-vuejs-modal-component-1

Call the component in your page

For example, I want to call this component on my index page. First of all, import the Vue component first and set into the components object.

Make sure you're calling the correct path.

App.vue

<script>
import ModalDirection from "@/components/common/Modal";
export default {
  components: {
    ModalDirection,
  },
};
</script>

You've successfully imported a component into the page. You can use the component by using this tag.

<modal-direction></modal-direction>

Or

<ModalDirection></ModalDirection>

App.vue

<template>
  <div>
    <modal-direction></modal-direction>
  </div>
</template>
 
<script>
import ModalDirection from "@/components/common/Modal";
export default {
  components: {
    ModalDirection,
  },
};
</script>

Add a function to the Modal

One of the features of modal is it's able to be visible or not. It'll be visible when other element triggers a function. How to control the function between component 🤔?

We need to add the new data binding in the App.vue, and we called it modalOpen and set it to false. We don't want the modal visible when the user enters the page.

App.vue

<script>
import ModalDirection from "@/components/common/Modal";
export default {
  components: {
    ModalDirection,
  },
  data() {
    return {
      modalOpen: false,
    };
  },
};
</script>

Let's create a button to toggle the value of modalOpen.

App.vue

<template>
  <div>
    <button class="btn" @click="openModal">Open Modal</button>
    <modal-direction></modal-direction>
  </div>
</template>
 
<script>
import ModalDirection from "@/components/common/Modal";
export default {
  components: {
    ModalDirection,
  },
  data() {
    return {
      modalOpen: false,
    };
  },
  methods: {
    openModal() {
      this.modalOpen = !this.modalOpen;
    },
  },
};
</script>

Then, assigned the v-model - modalOpen to the ModalDirection component.

<modal-direction v-model="modalOpen"></modal-direction>

Receive a data from parent - in component

Now, the data has been passed into the component. Let’s edit our component to make sure it well received. We’ll write a prop to accept the data from the directModal - model that we just wrote just now.

Modal.vue

<template>
  <div class="modal">
    <div class="container">
      <div class="modal__title">Direction</div>
      <p>Get a direction with your favourite apps</p>
      <a href="#" class="btn gmaps">
        <img src="https://img.icons8.com/color/420/google-maps.png" /> Google
        Maps
      </a>
      <a href="#" class="btn waze">
        <img src="https://img.icons8.com/color/420/waze.png" /> Waze
      </a>
      <button class="mt-3 border-b border-teal font-semibold">Close</button>
    </div>
  </div>
</template>
 
<script>
export default {
    name: 'Modal',
    props: {
        value: {
            required; true
        }
    }
};
</script>
 
<style lang="css" scoped>
.modal {
  background-color: rgba(0, 0, 0, 0.7);
}
</style>

Cool. Now we’re able to access the data from the parent 🎉. You can access the data from the v-model by using this code.

Template tags

{{ value }}

Script Tags

{
  {
    this.value;
  }
}

Control the modal visibility

We should show the modal if the component receives true from the parent. Right now, the modal is full visibility. We should control the visibility of the modal from the value.

Luckily, we have the v-show to simplify all of this. Just add the v-show tag in the modal tag.

Modal.vue

<template>
  <div class="modal" v-show="value">
    <div class="container">
      <div class="modal__title">Direction</div>
      <p>Get a direction with your favourite apps</p>
      <a href="#" class="btn gmaps">
        <img src="https://img.icons8.com/color/420/google-maps.png" /> Google
        Maps
      </a>
      <a href="#" class="btn waze">
        <img src="https://img.icons8.com/color/420/waze.png" /> Waze
      </a>
      <button class="mt-3 border-b border-teal font-semibold">Close</button>
    </div>
  </div>
</template>

Modal only visible if the value is set to true.

Send the signal to the parent

Cool, now the modal appears when we clicked the button. Unluckily, there is one last problem. How do we close the modal?

Right now, the parent is controlling the modal from the value - v-model. For now, let’s add method to the button close to pass the data to the parent using custom event.

Modal.vue

<template>
  <div class="modal" v-show="value">
    <div class="container">
      <div class="modal__title">Direction</div>
      <p>Get a direction with your favourite apps</p>
      <a href="#" class="btn gmaps">
        <img src="https://img.icons8.com/color/420/google-maps.png" /> Google
        Maps
      </a>
      <a href="#" class="btn waze">
        <img src="https://img.icons8.com/color/420/waze.png" /> Waze
      </a>
      <button
        @click.prevent="close"
        class="mt-3 border-b border-teal font-semibold"
      >
        Close
      </button>
    </div>
  </div>
</template>
 
<script>
export default {
    name: 'Modal',
    props: {
        value: {
            required: true
        }
    }
      methods: {
        close() {
          this.$emit("input", !this.value);
        }
    }
};
</script>
 
<style lang="css" scoped>
.modal {
  background-color: rgba(0, 0, 0, 0.7);
}
</style>

💡 Quick tips: Use .prevent to disabled default action of the event will not be triggered. It can be used for button, form, anchor link, and many more.

Since, we’re passing the data through v-model in the component, by the default the event will be called as an input as the event.

_how-to-build-a-reusable-vuejs-modal-component-2

Congratulations 🎉

Now, the modal is working. You can turn it on and off by using a component. The best part is reusable. You may use it in a different page without writing the code again.

Source Code

Modal.vue

<template>
  <div class="modal" v-show="value">
    <div class="container">
      <div class="modal__title">Direction</div>
      <p>Get a direction with your favourite apps</p>
      <a href="#" class="btn gmaps">
        <img src="https://img.icons8.com/color/420/google-maps.png" /> Google
        Maps
      </a>
      <a href="#" class="btn waze">
        <img src="https://img.icons8.com/color/420/waze.png" /> Waze
      </a>
      <button
        @click.prevent="close"
        class="mt-3 border-b border-teal font-semibold"
      >
        Close
      </button>
    </div>
  </div>
</template>
 
<script>
export default {
    name: 'Modal',
    props: {
        value: {
            required: true
        }
    }
      methods: {
        close() {
          this.$emit("input", !this.value);
        }
    }
};
</script>
 
<style lang="css" scoped>
.modal {
  background-color: rgba(0, 0, 0, 0.7);
}
</style>

App.vue

<template>
  <div>
    <button class="btn" @click="openModal">Open Modal</button>
    <modal-direction v-model="modalOpen"></modal-direction>
  </div>
</template>
 
<script>
import ModalDirection from "@/components/common/Modal";
export default {
  components: {
    ModalDirection,
  },
  data() {
    return {
      modalOpen: false,
    };
  },
  methods: {
    openModal() {
      this.modalOpen = !this.modalOpen;
    },
  },
};
</script>

You can directly pass the variable into the inline-style

I’ve recorded a video to show how this works.