# Modal

The CModal component can be used to render modals/dialogs. CModal is highly customizable. By default only minimal styles are applied.

# Installation

The @vue-cdk/modal package can be installed via NPM/Yarn:

$ npm install @vue-cdk/modal --save

# Usage

@vue-cdk/modal exposes a Vue plugin that you can use like this:

import Modal from '@vue-cdk/modal'
import Vue from 'vue'

Vue.use(Modal)

The plugin makes two components globally available:

  • CModal: Use this component to render a modal. Modals are hidden/inactive by default.
  • CModalOverlay: This component is rendered behind every modal. By default is renders a dark, translucent background. Usually you never have to interact with CModalOverlay. CModalOverlay exists in order to customize the overlay used for modals.

# Import the required Styles

Modals require CSS to work properly. @vue-cdk/modal ships with CSS that you have to import:

import '@vue-cdk/modal/style/index.css'

Styles are REQUIRED

Make sure to import @vue-cdk/modal/style/index.css. Otherwise your modals will not work properly.

# Examples

Modals can be used in many different ways. Each example highlights a different aspect of the modal package.

# Simple Modal

The following example shows how a default modal looks like.

outside
outside
Show Code
<template>
  <div>
    <div>outside</div>
    <input tabindex="0" />
    <button @click="open = true">Open Modal</button>
    <CModal :open.sync="open">
      <template #default="{ close }">
        <div style="background-color: white">
          <div>modal</div>
          <button @click="close">close</button>
          <div>
            <input />
          </div>
        </div>
      </template>
    </CModal>

    <div>outside</div>
    <input tabindex="0" />
  </div>
</template>

<script>
import CModal from '@vue-cdk/modal'
import '@vue-cdk/modal/style/index.css'
export default {
  mixins: [CModal()],
  data() {
    return {
      open: false,
    }
  },
}
</script>

# Nested Modals

Modals can be nested.

outside
outside
Show Code
<template>
  <div>
    <div>outside</div>
    <input tabindex="0" />
    <button @click="open = true">Open Modal</button>

    <CModal :open.sync="open">
      <template #default="{ close }">
        <div style="background-color: white">
          <div>modal</div>
          <button @click="close">Close</button>
          <button @click="nestedOpen = true">Open Nested Modal</button>
          <div>
            <input />
          </div>
        </div>
      </template>
    </CModal>

    <CModal :open.sync="nestedOpen">
      <template #default="{ close }">
        <div style="background-color: white">
          <div>modal</div>
          <button @click="close">close</button>
          <button @keydown.esc="close">x</button>
          <div>
            <input />
          </div>
        </div>
      </template>
    </CModal>

    <div>outside</div>
    <input tabindex="0" />
  </div>
</template>

<script>
import CModal from '@vue-cdk/modal'
import '@vue-cdk/modal/style/index.css'
export default {
  mixins: [CModal()],
  data() {
    return {
      open: false,
      nestedOpen: false,
    }
  },
}
</script>

# Custom Overlay

You can customize the overlay by proviing an overlay–slot. If you just want to customize the styling adding your own class is all you need to do.

Lazily render CModalOverlay

Make sure to use v-if="open" on CModalOverlay. Otherwise the modal and overlay are not rendered lazily. This is not an issue per se but if you have many modals (for example in a long list/table) you may experience performance issues.

Show Code
<template>
  <div>
    <button @click="open = true">Open Modal</button>
    <CModal :open.sync="open">
      <template #overlay>
        <CModalOverlay v-if="open" class="custom-overlay">
          <div style="background-color: white">
            <div>modal</div>
            <button @click="open = false">close</button>
            <div>
              <input />
            </div>
          </div>
        </CModalOverlay>
      </template>
    </CModal>
  </div>
</template>

<script>
import CModal from '@vue-cdk/modal'
import '@vue-cdk/modal/style/index.css'
export default {
  mixins: [CModal()],
  data() {
    return {
      open: false,
    }
  },
}
</script>

<style scoped>
.custom-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: radial-gradient(circle at 100%, #333, #333 50%, #eee 75%, #333 75%);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1001 !important;
}
</style>

# Nice Modal

You may have noticed that modals look kind of ugly by default. This does not have to be that way. Simply style the modal and its content as you wish to make it nicer.

Show Code
<template>
  <div>
    <button @click="open = true">Open Modal</button>

    <CModal :open.sync="open">
      <div class="modal">
        <div class="modal-title">Delete Account?</div>
        <div class="modal-content">
          Are you sure to delete your account? You can also just deactivate your account and
          activate it later on if you just want to get a little break.
        </div>
        <div class="modal-actions">
          <button class="modal-action modal-confirm" @click="open = false">
            <span class="modal-action__title">Delete</span>
          </button>
          <button class="modal-action modal-cancel" @click="open = false">
            <span class="modal-action__title">Cancel</span>
          </button>
        </div>
      </div>
    </CModal>
  </div>
</template>

<script>
import CModal from '@vue-cdk/modal'
import '@vue-cdk/modal/style/index.css'
export default {
  mixins: [CModal()],
  data() {
    return {
      open: false,
    }
  },
}
</script>

<style scoped>
.modal {
  max-width: 30vw;
  background-color: white;
  padding: 2rem 1.5rem;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
    'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
    'Noto Color Emoji';
  border-radius: 0.2rem;
}
.modal {
  box-shadow: 0px 0px 68px -15px rgba(0, 0, 0, 0.8);
  transition: box-shadow 0.3s ease-in-out;
}
.modal:hover {
  box-shadow: 0px 10px 68px -10px rgba(0, 0, 0, 1);
}
.modal-title {
  font-size: 1.3rem;
  font-weight: 500;
  margin-bottom: 1rem;
}
.modal-content {
  font-size: 1rem;
  margin: 1rem 0rem;
  line-height: 1.7rem;
}
.modal-actions {
  display: flex;
  justify-content: flex-end;
}
.modal-action {
  margin-left: 1rem;
  font-size: 1rem;
  padding: 0.9rem 1.2rem;
  border-radius: 0.33rem;
  color: white;
  cursor: pointer;
  outline: none;
  transition: background-color 0.3s ease-in-out;
}
.modal-confirm {
  border: 1px solid rgb(84, 119, 0);
  color: rgb(84, 119, 0);
  background-color: rgb(245, 255, 221);
}
.modal-confirm:hover {
  background-color: rgb(224, 255, 151);
}
.modal-confirm:focus {
  box-shadow: 0px 0px 5px 0px rgba(84, 119, 0, 150);
}
.modal-cancel {
  border: 1px solid rgb(119, 24, 0);
  color: rgb(119, 24, 0);
  background-color: rgb(255, 225, 221);
}
.modal-cancel:hover {
  background-color: rgb(255, 189, 180);
}
.modal-cancel:focus {
  box-shadow: 0px 0px 5px 0px rgba(201, 131, 122, 200);
}
</style>

Playground