Modal (TModal)

VueJs Modal component with configurable classes and infinite variants. Friendly with utility-first frameworks like TailwindCSS.

Playground:


Basic example

<t-modal
  header="Title of the modal"
>
  Content of the modal.
  <template v-slot:footer>
    <div class="flex justify-between">
      <t-button type="button">
        Cancel
      </t-button>
      <t-button type="button">
        Ok
      </t-button>
    </div>
  </template>
</t-modal>
Title of the modal
Content of the modal.

Props

PropertyTypeDefault valueDescription
nameStringundefinedUse to open and close the modal by his name
value (v-model)BooleanfalseWill show the modal according to the value
headerStringundefinedThe content of the header
footerStringundefinedThe content of the footer
clickToCloseBooleantrueIf true, the modal will close when the user click the overlay
escToCloseBooleantrueIf true, the modal will close when the user press the esc button
noBodyBooleanfalseIf true, the modal will be rendered without body, header, and footer
hideCloseButtonBooleanfalseIf true, the modal will hide the close button
disableBodyScrollBooleantrueWhen set, the body of the page will be locked so a large modal can be scrollable
focusOnOpenBooleantrueWhen set, the modal will be focused after opened. This is necessary if you want that the modal close on when the user press theesc key
fixedClassesObject{...} (see below)The default CSS Fixed classes shared for all variants
classesObject{...} (see below)The default CSS classes
variantsObjectundefinedThe different variants of classes the component have
variant[String, Object]undefinedThe variant that should be used

Classes and variants format

This component expects an object with classes named after every child element.

The properties in that object are the following:

PropertyDescription
overlayThe overlay that covers the screen
wrapperDiv that wraps the modal
modalThe classes of the modal
bodyBody wrapper class
headerHeader wrapper class
footerFooter wrapper class
closeClose button classes
closeIconClose icon classes

Default fixed classes

As you may know, the fixed classes are merged with the different variants and default classes.

The default fixedClasses on this component are the ones you usually will need as a minimum to ensure this component works as expected.

{
  overlay: 'overflow-auto scrolling-touch left-0 top-0 bottom-0 right-0 w-full h-full fixed',
  wrapper: 'relative mx-auto',
  modal: 'overflow-visible relative ',
  close: 'flex items-center justify-center',
};

Default classes

Classes that define the default style of the component.

{
  overlay: 'z-40 bg-black bg-opacity-50',
  wrapper: 'z-50 max-w-lg px-3 py-12',
  modal: 'bg-white shadow rounded',
  body: 'p-3',
  header: 'border-b border-gray-100 p-3 rounded-t',
  footer: 'bg-gray-100 p-3 rounded-b',
  close: 'bg-gray-100 text-gray-600 rounded-full absolute right-0 top-0 -m-3 h-8 w-8 transition duration-100 ease-in-out hover:bg-gray-200 focus:ring-2 focus:ring-blue-500 focus:outline-none focus:ring-opacity-50',
  closeIcon: 'fill-current h-4 w-4',
  overlayEnterClass: 'opacity-0',
  overlayEnterActiveClass: 'transition ease-out duration-100',
  overlayEnterToClass: 'opacity-100',
  overlayLeaveClass: 'opacity-100',
  overlayLeaveActiveClass: 'transition ease-in duration-75',
  overlayLeaveToClass: 'opacity-0',
  enterClass: '',
  enterActiveClass: '',
  enterToClass: '',
  leaveClass: '',
  leaveActiveClass: '',
  leaveToClass: '',
}

Margin and width

If you need to add some margin or spacing between the modal and the screen or define a different width, the wrapper attribute is the most appropriate. Example:

{
  // ...
  wrapper: 'mt-20 px-10 max-w-md .. z-50 relative mx-auto',
  // ...
}

Full Example

{
  fixedClasses: {
    overlay: 'z-40  overflow-auto scrolling-touch left-0 top-0 bottom-0 right-0 w-full h-full fixed bg-opacity-50',
    wrapper: 'relative mx-auto z-50 max-w-lg px-3 py-12',
    modal: 'overflow-visible relative  rounded',
    body: 'p-3',
    header: 'border-b p-3 rounded-t',
    footer: ' p-3 rounded-b',
    close: 'flex items-center justify-center rounded-full absolute right-0 top-0 -m-3 h-8 w-8 transition duration-100 ease-in-out focus:ring-2 focus:ring-blue-500 focus:outline-none focus:ring-opacity-50'
  },
  classes: {
    overlay: 'bg-black',
    wrapper: '',
    modal: 'bg-white shadow',
    body: 'p-3',
    header: 'border-gray-100',
    footer: 'bg-gray-100',
    close: 'bg-gray-100 text-gray-600 hover:bg-gray-200',
    closeIcon: 'fill-current h-4 w-4',
    overlayEnterClass: 'opacity-0',
    overlayEnterActiveClass: 'transition ease-out duration-100',
    overlayEnterToClass: 'opacity-100',
    overlayLeaveClass: 'opacity-100',
    overlayLeaveActiveClass: 'transition ease-in duration-75',
    overlayLeaveToClass: 'opacity-0',
    enterClass: '',
    enterActiveClass: '',
    enterToClass: '',
    leaveClass: '',
    leaveActiveClass: '',
    leaveToClass: ''
  },
  variants: {
    danger: {
      overlay: 'bg-red-100',
      header: 'border-red-50 text-red-700',
      close: 'bg-red-50 text-red-700 hover:bg-red-200 border-red-100 border',
      modal: 'bg-white border border-red-100 shadow-lg',
      footer: 'bg-red-50'
    }
  }
}

Interact with the modal

You can open/close the modal in 3 ways:

1. Using the value or v-model

<template>
  <div> 
    <t-modal v-model="showModal">hello world</t-modal>
    <button @click="showModal=true" type="button">Show modal</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      showModal: false
    }
  }
}
</script>

2. Calling the show/hide methods inside the modal

<div> 
  <t-modal ref="modal">hello world</t-modal>
  <button @click="$refs.modal.show()" type="button">Show modal</button>
  <button @click="$refs.modal.hide()" type="button">Hide modal</button>
</div>

3. Open the modal by his name

This library includes some global methods that you can use to show/hide a named modal. To use it, you just need to give the modal a name, and then you can show and hide it with the $modal.show('name-of-your-modal') and $modal.hide('name-of-your-modal') respectively.

<div> 
  <t-modal name="my-modal">hello world</t-modal>
  
  <button @click="$modal.show('my-modal')" type="button">Show modal</button>
  <button @click="$modal.hide('my-modal')" type="button">Hide modal</button>
</div>

Note:

The this.$modal.show('my-modal') accept some extra parameters that are passed to the before-open event and you can use to pass data to the modal. Consider the following example:

<template>
  <div>
    <t-modal
      name="modal-name"
      @before-open="onBeforeOpen"
    >
      hello {{ user ? user.name : '' }}
    </t-modal>
    <button type="button" @click="$modal.show('modal-name', { user: { name: 'Alfonso'} })">
      Show modal
    </button>
  </div>
</template>

<script>
export default {
  data () {
    return {
      user: undefined
    }
  },
  methods: {
    onBeforeOpen ({ params, cancel }) {
      // you can add a condition to cancel the modal opening
      if (false) {
        cancel()
      }

      this.user = params.user
    }
  }
}
</script>

Events

NameParamsDescription
before-open{ params, cancel }Emits while modal is still invisible, but it was added to the DOM
opened{ params }Emits after modal became visible or started transition
before-close{ cancel }Emits before modal is going to be closed
closedEmits right before modal is destroyed
inputEmits when the v-model value change
The `cancel` param is a method you can use to stop the modal from opening or closing.

Slots

Slotdescription
defaultcontent of the modal
headercontent of the header
footercontent of the footer
closeContent of the close button

Sign up for our newsletter

Stay up-to-date on news and updates about this project by email.

I will never spam or share your email under any circustance.