Dialog (TDialog)

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

Use it for alerts, confirmation, or prompt dialogs, open it programmatically, or add the component normally as a Vue component.


Basic example

Delete user?

This action cannot be undone.

As Vue component

Add the Dialog in your template as any Vue component if you want to have more control over the content of the dialog.

For example, it allows you to use any custom HTML and reactive content by using the slots and interact with it by using the built-in functions like this.$dialog.show('named-dialog') similar to the way you interact with the Modal. This is especially useful for forms.

<!-- Note that the visual style of the example comes from a custom theme made for this docs -->
<t-dialog
  name="named-dialog"
  icon="question"
  type="confirm"
  variant="demo"
>
  <template slot="title">
    Delete user?
  </template>

  <p>This action cannot be undone.</p>

  <template slot="icon">
    <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7a4 4 0 11-8 0 4 4 0 018 0zM9 14a6 6 0 00-6 6v1h12v-1a6 6 0 00-6-6zM21 12h-6" /></svg>
  </template>
</t-dialog>

Open the dialog programmatically

You can use the build it global methods to trigger a dialog at any moment, these methods return a promise that you can use to handle the results of the dialog.

Confirm

this.$dialog.confirm('Delete user?', 'This action cannot be undone.', 'info')
  .then((result) => {
    console.log(result)
  })
// Or 
this.$dialog.confirm({
  title: 'Delete user?',
  text: 'This action cannot be undone.',
  icon: 'info',
  // variant: 'my-confirm',
  // ...More props
}).then((result) => {
  console.log(result)
})

Example:

Prompt

this.$dialog.prompt('New password', 'Include one number and one special character.', 'question')
  .then((result) => {
    console.log(result)
  })
// Or 
this.$dialog.prompt({
  title: 'New password',
  text: 'Include one number and one special character.',
  icon: 'question',
  // variant: 'my-question',
  // ...More props
}).then((result) => {
  console.log(result)
})

Alert

this.$dialog.alert('Server overheating', 'Please add an ice or something', 'warning')
  .then((result) => {
    console.log(result)
  })
// Or 
this.$dialog.alert({
  title: 'Server overheating',
  text: 'Please add an ice or something',
  icon: 'warning',
  // variant: 'my-alert',
  // ...More props
}).then((result) => {
  console.log(result)
})

Props or options

PropertyTypeDefault valueDescription
value (v-model)BooleanfalseIf set will show the Dialog
typeString'alert'Dialog type ('alert', 'prompt' or 'confirm')
nameStringundefinedUnique name for the dialog. (Useful for toggle it with the $dialog.show(name) and $dialog.hide(name) methods)
titleTagString'h3'HTML Tag used for the dialog title
titleStringundefinedTitle of the dialog
iconStringundefinedIcon of the dialog ('success', 'error', 'warning', 'info' or 'question'))
textTagString'p'HTML Tag used for the dialog text
textStringundefinedText content of the dialog
clickToCloseBooleantrueIf set will close te dialog when the user clicks the overlay (clicks outside)
escToCloseBooleantrueIf set will close te dialog when the user press the esc key
cancelButtonTextString'Cancel'Cancel button text
cancelButtonAriaLabelStringundefinedCancel button aria label
okButtonTextString'OK'Ok button text
okButtonAriaLabelStringundefinedOk button aria label
showCloseButtonBooleanfalseIf set will show a close button with an icon
disableBodyScrollBooleantrueIf set, the body of the page will be locked so a large dialog can be scrollable
focusOnOpenBooleantrueIf set, the dialog will be focused after opened. This is necessary if you want that the dialog close on when the user press theesc key
preConfirmFunctionundefinedFunction to run before submit the dialog, it accepts a promise
inputAttributesObjectundefined(Prompt only) attributes of of the text input
inputTypeString'text'(Prompt only) type of the prompt input (accepts 'select', 'radio', 'checkbox' and all the valid type value for text input) input
inputValidatorFunctionundefined(Prompt only) Function for validate the value of the prompt, receives the prompt value and should return an error message or empty if no erros. It accepts a promise
inputValue[String, Array]undefined(Prompt only) Default value of the input
inputOptions[Array, Object]undefined(Prompt only and only applies to select, radio and checkbox inputType) set of options in any of the valid format the the TSelect accepts
inputPlaceholderStringundefined(Prompt only) Placeholder for the prompt input, and label in the case of a single checkbox
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
closeClose button
closeIconClose button SVG icon
overlayThe overlay that covers the screen
wrapperDiv that wraps the dialog
dialogDialog
bodyDialog body
buttonsButton wrapper
iconWrapperIcon wrapper
iconSVG icon
contentWraps the title, text, and prompt input
titleWrapperWraps the title
titleTitle tag
textWrapperWraps the text content
textText tag
cancelButtonCancel button
okButtonOk Button
inputWrapperWraps the prompt input
inputPrompt input
selectPrompt select
radioWrapperPrompt radio inputs wrapper
radioPrompt radio input
radioTextPrompt radio text
checkboxWrapperPrompt checkbox wrapper
checkboxPrompt checkbox
checkboxTextPrompt checkbox text
errorMessageError message (for invalid prompts)
busyWrapperDivs that appears when the prompt is busy (to use as overlay)
busyIconIcon inside the busy wrapper

Vue transition classes

Property
overlayEnterClass
overlayEnterActiveClass
overlayEnterToClass
overlayLeaveClass
overlayLeaveActiveClass
overlayLeaveToClass
enterClass
enterActiveClass
enterToClass
leaveClass
leaveActiveClass
leaveToClass

Default fixed classes

The fixed classes have a default value with the minimum CSS classes this component needs to work as expected. If you replace the classes or create variants, you should keep the wrapper and overlay classes. Those classes are related to the display and position.

{
  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',
  dialog: 'overflow-visible relative',
};

Default classes

Classes that define the default style of the component.

{
  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',

  overlay: 'z-40 bg-black bg-opacity-50',
  wrapper: 'z-50 max-w-lg px-3 py-12',
  dialog: 'bg-white shadow rounded text-left',

  body: 'p-3 space-y-3',
  buttons: 'p-3 flex space-x-4 justify-center bg-gray-100 rounded-b',

  iconWrapper: 'bg-gray-100 flex flex-shrink-0 h-12 items-center justify-center rounded-full w-12 mx-auto',
  icon: 'w-6 h-6 text-gray-500',
  content: 'w-full flex justify-center flex-col',

  titleWrapper: '',
  title: 'text-lg font-semibold text-center',

  textWrapper: 'text-left w-full',
  text: '',

  cancelButton: 'block px-4 py-2 transition duration-100 ease-in-out bg-white border border-gray-300 rounded shadow-sm hover:bg-gray-100 focus:border-gray-100 focus:ring-2 focus:ring-blue-500 focus:outline-none focus:ring-opacity-50 disabled:opacity-50 disabled:cursor-not-allowed w-full max-w-xs',
  okButton: 'block px-4 py-2 text-white transition duration-100 ease-in-out bg-blue-500 border border-transparent rounded shadow-sm hover:bg-blue-600 focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:outline-none focus:ring-opacity-50 disabled:opacity-50 disabled:cursor-not-allowed w-full max-w-xs',

  inputWrapper: 'mt-3 flex items-center space-x-3',

  input: 'block w-full px-3 py-2 text-black placeholder-gray-400 transition duration-100 ease-in-out bg-white border border-gray-300 rounded shadow-sm focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:outline-none focus:ring-opacity-50 disabled:opacity-50 disabled:cursor-not-allowed w-full',
  select: 'block w-full px-3 py-2 text-black placeholder-gray-400 transition duration-100 ease-in-out bg-white border border-gray-300 rounded shadow-sm focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:outline-none focus:ring-opacity-50  disabled:opacity-50 disabled:cursor-not-allowed w-full',

  radioWrapper: 'flex items-center space-x-2',
  radio: 'text-blue-500 transition duration-100 ease-in-out border-gray-300 shadow-sm focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:outline-none focus:ring-opacity-50 focus:ring-offset-0  disabled:opacity-50 disabled:cursor-not-allowed',
  radioText: '',

  checkboxWrapper: 'flex items-center space-x-2',
  checkbox: 'text-blue-500 transition duration-100 ease-in-out border-gray-300 rounded shadow-sm focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:outline-none focus:ring-opacity-50 focus:ring-offset-0  disabled:opacity-50 disabled:cursor-not-allowed',
  checkboxText: '',

  errorMessage: 'text-red-500 block text-sm',

  busyWrapper: 'absolute bg-opacity-50 bg-white flex h-full items-center justify-center left-0 top-0 w-full',
  busyIcon: 'animate-spin h-6 w-6 fill-current text-gray-500',

  overlayEnterClass: '',
  overlayEnterActiveClass: 'opacity-0 transition ease-out duration-100',
  overlayEnterToClass: 'opacity-100',
  overlayLeaveClass: 'transition ease-in opacity-100',
  overlayLeaveActiveClass: '',
  overlayLeaveToClass: 'opacity-0 duration-75',

  enterClass: '',
  enterActiveClass: '',
  enterToClass: '',
  leaveClass: '',
  leaveActiveClass: '',
  leaveToClass: '',
}

Margin and width

If you need to add some margin or spacing between the dialog 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',
  // ...
}

Toggle the dialog programmatically

You can open the dialog programmatically by using the built-in functions.

These functions are $dialog.alert, $dialog.prompt, and $dialog.confirm, they all work the same and the only difference is the type of dialog that you will open.

Method parameters

For simple dialogs, you can pass strings to the method parameters with the title as a required first parameter and the optional text and icon as the rest of the parameters.

Example:

// Text parameters
this.$dialog.alert('Title of the dialog');
// Or
this.$dialog.alert('Title of the dialog', 'text of the dialog (optional)', 'iconName (optional)');

You can also pass an object that accepts any of the props of this component

Example:

// Text parameters
this.$dialog.alert({
  title: 'Title of the dialog',
  text: 'text of the dialog',
  icon: 'question',
  variant: 'danger',
  textTag: 'span',
  // .... basically any prop
});

Dialog response

The dialog will return a promise that eventually will return and object with some useful data related with the user interaction.

The object returned will look like this:

{
  hideReason: "ok",
  isOk: true,
  isCancel: false,
  isDismissed: false
  // Only in prompts
  input: DialogInput;
  // When using a preConfirm function
  response: any;
}
PropertyDescription
hideReasonThe dialog close reason
isOkIf the ok button was pressed
isCancelIf the cancel button was pressed
isDismissedIf the dialog was closed for any other reason
inputWhen using a prompt the result of the user prompt
responseWhen using the preConfirm function in a prompt the result of the preconfirm response

Hide reason

The possible hide reasons are the following:

ReasonDescription
'outside'Closed because the user clicks outside
'close'Closed because the user press the close button
'esc'Closed because the user press the esc key
'cancel'The user presses the cancel button
'ok'The user press the ok button
'method'The user closed the dialog with the $dialog.hide method
'value'The dialog was closed because the v-model was set to form

Toggle the dialog as a vue component

When using the Dialog as a normal vue component you can open/close the dialog in 3 ways:

1. Using the value or v-model

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

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

2. Calling the show/hide methods inside the dialog

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

3. Open the dialog by his name

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

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

Note:

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

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

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

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

Events

NameParamsDescription
before-open{ params, cancel }Emits while the dialog is still invisible, but it was added to the DOM
opened{ params }Emits after dialog became visible or started transition
before-close{ cancel, event, reason, input?, response? }Emits before the dialog is going to be closed (include some of the data of the dialog response)
closed{ hideReason, isOk, isCancel, isDismissed, input?, response? }Emits right before dialog is destroyed (include dialog response)
inputbooleanEmits when the v-model value change
changebooleanEmits when the v-model value change
The `cancel` param is a method you can use to stop the dialog from opening or closing.

Slots

SlotDescription
defaultContent of the dialog
titleContent of the title
iconContent of the icon
loaderContent of the loading div
closeButtonContent of the close button
buttonsContent of the buttons section

Buttons scoped slot

The buttons scoped slot includes some data that is necessary to create your own buttons

AttributeType
cancelButtonAriaLabelSame value as the prop
okButtonAriaLabelSame value as the prop
cancelButtonTextSame value as the prop
okButtonTextSame value as the prop
okButtonClassSame value as the prop
cancelButtonClassSame value as the prop
dialogTypeSame value as the prop
cancelMethod for trigger the "cancel" behavior
okMethod for trigger the "ok" behavior

Slots Example

<t-dialog
      name="named-dialog"
  :icon="icon"
  title="Remove user?"
>
  <template slot="title">
    yeah yeah
  </template>

  <template slot="icon">
    <svg
      class="w-6 h-6"
      fill="none"
      stroke="currentColor"
      viewBox="0 0 24 24"
      xmlns="http://www.w3.org/2000/svg"
    ><path
      stroke-linecap="round"
      stroke-linejoin="round"
      stroke-width="2"
      d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"
    /></svg>
  </template>

  <template
    slot="buttons"
    slot-scope="{ ok, cancel }"
  >
    <a
      href="#"
      @click.prevent="ok"
    >Ok do it</a>
    <a
      href="#"
      @click.prevent="cancel"
    >Cancel</a>
  </template>

  This is the content of the dialog.
</t-dialog>

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.