Modal
The VModal
component is used to create modal or dialog. It is based on @headlessui/vue
dialog component.
Usage
Basic Usage
To use the VModal
component, just use it in the template.
INFO
The VModal
component is registered globally when you install with @morpheme/ui
. So you don't need to import it manually.
Confirm
Use confirm
prop to make modal confirmable. You can also customize the confirm text with confirmText
prop, color with confirmColor
prop and even more with confirmProps
.
Hide Header
Use hide-header
prop to hide the modal header.
Hide Footer
Use hide-footer
prop to hide the modal footer.
Hide X Button
Use hide-x-button
prop to hide the modal close button.
Fullscreen
Use fullscreen
prop to make modal fullscreen.
Centered
Use centered
prop to make the modal centered of the page.
Loading
Use loading
prop to set modal loading state. When loading
is true, modal can not be closed.
Persistent
Use persistent
prop to prevent closing modal when clicking the overlay.
Custom Width
Use width
prop set modal width and use max-width
prop to set modal max width.
Custom Class
We can also customize modal via classes props. This is useful when working with Tailwind CSS.
modal-class
: To set class on modal panelheader-class
: To set class on modal headertitle-class
: To set class on modal title onlybody-class
: To set class on modal bodyfooter-class
: To set class on modal footer
Custom Style
We can also customize modal via CSS Properties.
Declarative Modal
Starting from version v1.0.0-beta.11
, we have introduced a new declarative approach to use the modal component, providing you with enhanced flexibility. This approach involves breaking down the modal component into five separate components, each serving a specific purpose. To utilize this feature, you will need to manually import these components.
Component List
The modal components are as follows:
Modal
ModalHeader
ModalTitle
ModalBody
ModalFooter
Usage
Unlike before, these components are not auto-imported. Therefore, you must import them individually based on your requirements.
Here's a brief overview of each modal component and its purpose:
Modal
: This is the main component that serves as the container for the entire modal dialog.ModalHeader
: Use this component to display the header section of the modal. Typically, it contains the title and close button.ModalTitle
: This component is used to display the title of the modal. It is usually placed inside theModalHeader
.ModalBody
: This component allows you to add content to the body of the modal. Any information or forms you wish to present should be placed within this component.ModalFooter
: The footer component is utilized to include any additional elements at the bottom of the modal, such as action buttons (e.g., Save, Cancel).
Example
Props
Name | Type | Default |
---|---|---|
title | string | 'Modal Header' |
confirm | boolean | false |
confirmColor | string | 'primary' |
confirmProps | object | '{}' |
confirmText | string | Confirm |
closeText | string | Close |
closeProps | object | '{}' |
headerClass | string | '' |
titleClass | string | '' |
bodyClass | string | '' |
modalClass | string | '' |
footerClass | string | '' |
footerClass | string | '' |
hideHeader | boolean | false |
hideFooter | boolean | false |
Events
onConfirm
Event for confirmation modal.
<script setup lang="ts">
import {ref} from 'vue';
const isOpen = ref(false);
const onConfirm = async (e) => {
await approveRequest();
e.close();
};
const approveRequest = () => {
return new Promise((resolve: (value?: any) => void) => {
setTimeout(() => {
resolve();
}, 2000);
});
};
</script>
<template>
<VModal v-model="isOpen" confirm @confirm="onConfirm">
<template #activator="{open}">
<v-btn @click="open" color="error">Approve</v-btn>
</template>
<p>Are you sure want to approve this request?</p>
</VModal>
</template>
<script setup lang="ts">
import {ref} from 'vue';
const isOpen = ref(false);
const onConfirm = async (e) => {
await approveRequest();
e.close();
};
const approveRequest = () => {
return new Promise((resolve: (value?: any) => void) => {
setTimeout(() => {
resolve();
}, 2000);
});
};
</script>
<template>
<VModal v-model="isOpen" confirm @confirm="onConfirm">
<template #activator="{open}">
<v-btn @click="open" color="error">Approve</v-btn>
</template>
<p>Are you sure want to approve this request?</p>
</VModal>
</template>
Slots
default
The default
slot is used to place modal content/body. You can put your text or even HTML tags on it.
<template>
<VModal>
<p>Modal message</p>
</VModal>
</template>
<template>
<VModal>
<p>Modal message</p>
</VModal>
</template>
activator
The activator
slot is used to place modal activator. You can place button that trigger modal to open here.
Slot Props:
{
open: () => void
}
{
open: () => void
}
Example:
<template>
<VModal>
<template #activator="{open}">
<VBtn @click="open">Open Modal</VBtn>
</template>
<p>Modal message</p>
</VModal>
</template>
<template>
<VModal>
<template #activator="{open}">
<VBtn @click="open">Open Modal</VBtn>
</template>
<p>Modal message</p>
</VModal>
</template>
header
The header
slot is used to place modal header. Use this slot to customize modal header content.
<template>
<VModal>
<template #header>
<p>Custom Header</p>
</template>
<p>Modal message</p>
</VModal>
</template>
<template>
<VModal>
<template #header>
<p>Custom Header</p>
</template>
<p>Modal message</p>
</VModal>
</template>
footer
The footer
slot is used to place modal footer. Use this slot to customize modal footer content.
Slot Props:
{
loading: boolean
confirmProps: Record<string, any>
onConfirm: ((payload: ConfirmEventPayload) => any) & (() => void)
loading: boolean
close: () => void
}
{
loading: boolean
confirmProps: Record<string, any>
onConfirm: ((payload: ConfirmEventPayload) => any) & (() => void)
loading: boolean
close: () => void
}
Example:
<template>
<VModal>
<template #footer="{close}">
<VBtn>View Link</VBtn>
<VBtn @click="close">Close</VBtn>
</template>
<p>Modal message</p>
</VModal>
</template>
<template>
<VModal>
<template #footer="{close}">
<VBtn>View Link</VBtn>
<VBtn @click="close">Close</VBtn>
</template>
<p>Modal message</p>
</VModal>
</template>
CSS Variables
:root {
--v-modal-text-color: var(--color-gray-700);
--v-modal-bg-color: var(--color-white);
--v-modal-border-radius: 12px;
--v-modal-z-index: 30;
--v-modal-shadow: var(--effect-shadow-xl);
--v-modal-width: 25rem;
--v-modal-max-width: 100%;
/* content */
--v-modal-content-padding-x: var(--size-spacing-4);
--v-modal-content-padding-y: var(--size-spacing-4);
--v-modal-content-text-align: center;
/* panel */
--v-modal-panel-padding-x: var(--size-spacing-4);
--v-modal-panel-padding-y: var(--size-spacing-4);
--v-modal-margin-padding-x: var(--size-spacing-4);
--v-modal-margin-padding-y: var(--size-spacing-4);
--v-modal-content-text-align: center;
/* title */
--v-modal-title-font-weight: var(--font-weight-semibold);
--v-modal-title-font-size: var(--size-font-lg);
--v-modal-title-line-height: var(--size-font-xl);
--v-modal-title-letter-spacing: initial;
--v-modal-title-color: var(--color-gray-900);
/* body */
--v-modal-body-margin-top: var(--size-spacing-2);
--v-modal-body-text-align: left;
--v-modal-body-font-size: var(--size-font-sm);
--v-modal-body-line-height: var(--size-font-md);
/* footer */
--v-modal-footer-margin-top: var(--size-spacing-6);
--v-modal-footer-justify-content: flex-end;
--v-modal-footer-gap: var(--size-spacing-2);
// overlay
--v-modal-overlay-blur-size: 8px;
}
:root {
--v-modal-text-color: var(--color-gray-700);
--v-modal-bg-color: var(--color-white);
--v-modal-border-radius: 12px;
--v-modal-z-index: 30;
--v-modal-shadow: var(--effect-shadow-xl);
--v-modal-width: 25rem;
--v-modal-max-width: 100%;
/* content */
--v-modal-content-padding-x: var(--size-spacing-4);
--v-modal-content-padding-y: var(--size-spacing-4);
--v-modal-content-text-align: center;
/* panel */
--v-modal-panel-padding-x: var(--size-spacing-4);
--v-modal-panel-padding-y: var(--size-spacing-4);
--v-modal-margin-padding-x: var(--size-spacing-4);
--v-modal-margin-padding-y: var(--size-spacing-4);
--v-modal-content-text-align: center;
/* title */
--v-modal-title-font-weight: var(--font-weight-semibold);
--v-modal-title-font-size: var(--size-font-lg);
--v-modal-title-line-height: var(--size-font-xl);
--v-modal-title-letter-spacing: initial;
--v-modal-title-color: var(--color-gray-900);
/* body */
--v-modal-body-margin-top: var(--size-spacing-2);
--v-modal-body-text-align: left;
--v-modal-body-font-size: var(--size-font-sm);
--v-modal-body-line-height: var(--size-font-md);
/* footer */
--v-modal-footer-margin-top: var(--size-spacing-6);
--v-modal-footer-justify-content: flex-end;
--v-modal-footer-gap: var(--size-spacing-2);
// overlay
--v-modal-overlay-blur-size: 8px;
}
Standalone Installation
You can also install the Modal
component individually via @morpheme/modal
package:
npm i @morpheme/modal
npm i @morpheme/modal
<script setup lang="ts">
import VModal from '@morpheme/modal';
</script>
<template>
<VModal v-model="isOpen">
<template #activator="{open}">
<v-btn @click="open">Click Me</v-btn>
</template>
Hello World
</VModal>
</template>
<script setup lang="ts">
import VModal from '@morpheme/modal';
</script>
<template>
<VModal v-model="isOpen">
<template #activator="{open}">
<v-btn @click="open">Click Me</v-btn>
</template>
Hello World
</VModal>
</template>
Storybook
View Storybook documentation here.