Skip to content
This repository was archived by the owner on Feb 10, 2025. It is now read-only.

hoiheart/vue-universal-modal

Repository files navigation

vue-universal-modal

Universal modal plugin for Vue@3
Demo

⚠️ This plugin does not support Vue@2

Table of Contents

Introduction

vue-universal-modal plugin is based on the teleport.
It is very light and simple, but it provides essential features for modal use in applications.
(Such as Add & Remove, Visible & Hidden, Transition, Auto bind keyboard and mouse to close, Support SSR, A11Y...)
Here is the Demo

Features

  • Based on the teleport
  • Provides essential features for modal
  • A11Y
  • Support SSR (Insert rendering source into SSR context, Mount from Client-side)

Install plugin

npm install vue-universal-modal

Insert teleport element in your html

... <div id="app"></div> <!-- teleport target --> <div id="modals"></div> ...

Because SSR cannot be implemented by dynamically creating and ref referencing teleport elements, teleport targets must be inserted into html first.

And install plugin in vue application

import 'vue-universal-modal/dist/index.css'; import VueUniversalModal from 'vue-universal-modal'; app.use(VueUniversalModal, { teleportTarget: '#modals', });

Options

app.use(VueUniversalModal, { teleportTarget: '#my-modals', modalComponent: 'MyModal', });
name type detault description
teleportTarget (required) string Teleport target
modalComponent string 'Modal' Global modal component name

Usage modal

Insert the component wrapped with the modal component. (Slot based)

<template> <p> <button @click="showModal">Show modal</button> </p> <!-- If the option changed modal component the name  <MyModal>  --> <Modal v-model="isShow" :close="closeModal"> <div class="modal"> <p>Hello</p> <button @click="closeModal">close</button> </div> </Modal> </template> <script lang="ts"> import { defineComponent, ref } from 'vue';  export default defineComponent({  setup() {  const isShow = ref(false);   function showModal() {  isShow.value = true;  }   function closeModal() {  isShow.value = false;  }   return {  isShow,  showModal,  closeModal,  };  }, }); </script> <style scoped lang="scss"> .modal {  width: 300px;  padding: 30px;  box-sizing: border-box;  background-color: #fff;  font-size: 20px;  text-align: center; } </style>

v1.0.x -> v1.1.x change point

  • Use v-model instead of v-if for modal component insertion
  • If you control the insertion of components with v-if, the close animation will not work.
  • emitClose slot argument was deprecated.

props

name type detault description
close function () => {} Function to close a modal (apply when click dimmed)
disabled boolean false Handle just visibility (as in v-show)
options object {}

props.options

name type detault description
transition number | false 300 transition duration
closeClickDimmed boolean true Closes the modal when dimmed is clicked
closeKeyCode number | false 27 (esc) Closes the modal when press key
styleModalContent object {} Inject modal content style (.vue-universal-modal-content)

emit events

Supports emit properties for all transition events.

<template> <p> <button @click="showModal">Show modal</button> </p> <Modal v-model="isShow" :close="closeModal" @before-enter="beforeEnter" @after-enter="afterEnter" @before-leave="beforeLeave" @after-leave="afterLeave" > <div class="modal"> <p>Hello</p> <button @click="closeModal">close</button> </div> </Modal> </template> <script lang="ts"> import { defineComponent, ref } from 'vue';  export default defineComponent({  setup() {  const isShow = ref(false);   function showModal() {  isShow.value = true;  }   function closeModal() {  isShow.value = false;  }   function beforeEnter() {  console.log('before enter');  }   function afterEnter() {  console.log('after enter');  }   function beforeLeave() {  console.log('before leave');  }   function afterLeave() {  console.log('after leave');  }   return {  isShow,  showModal,  closeModal,  beforeEnter,  afterEnter,  beforeLeave,  afterLeave,  };  }, }); </script>

Handle global CSS

You can change it directly to your own style by referring to the source

.vue-universal-modal { /* Change dimmed color */ background-color: rgba(255, 255, 0, 0.3); } .vue-universal-modal-content { /* Align to top (flex-direction property value is set to column) */ justify-content: flex-start; }

Example