Modal
KModal is a pop-up modal component with a background overlay.
NOTE
If your use-case matches one of the scenarios below, consider using KPrompt instead:
- you need a simple pop-up dialog to ask user to confirm their action
- the user performed an action and you first require them to provide input text
- you don't need many customization options for a simple modal with action buttons
<KModal
:visible="modalVisible"
title="Modal"
@cancel="handleModalClose"
@proceed="handleModalProceed"
>
Modal is a pop-up element that temporarily interrupts the user's interaction with the main content.
</KModal>
Props
visible
A boolean that defines whether the modal is shown.
<template>
<KButton @click="modalVisible = true">Modal</KButton>
<KModal
:visible="modalVisible"
title="Modal"
@cancel="handleModalClose"
@proceed="handleModalClose"
/>
</template>
<script setup lang="ts">
const modalVisible = ref<boolean>(false)
const handleModalClose = () => {
modalVisible.value = false
}
</script>
title
A string to be displayed as modal title. Can also be slotted.
<KModal
title="Long modal title gets truncated with an ellipsis"
:visible="modalVisible"
@cancel="handleModalClose"
@proceed="handleModalProceed"
/>
actionButtonText
Text to be displayed in action button. Defaults to "Submit".
<KModal
action-button-text="Ok"
:visible="modalVisible"
title="Modal"
@cancel="handleModalClose"
@proceed="handleModalProceed"
/>
actionButtonAppearance
Appearance of action button. See KButton appearance
prop for more details. Defaults to primary
.
<KModal
action-button-appearance="danger"
:visible="modalVisible"
title="Modal"
@cancel="handleModalClose"
@proceed="handleModalProceed"
/>
actionButtonDisabled
By default the action button is enabled, but you can pass true
to this prop should you want to change that.
<KModal
:action-button-disabled="false"
:visible="modalVisible"
title="Modal"
@cancel="handleModalClose"
@proceed="handleModalProceed"
/>
cancelButtonText
Text to be displayed in cancel button. Defaults to "Cancel".
<KModal
cancel-button-text="Leave"
:visible="modalVisible"
title="Modal"
@cancel="handleModalClose"
@proceed="handleModalProceed"
/>
cancelButtonAppearance
Appearance of cancel button. See KButton appearance
prop for more details. Defaults to tertiary
.
<KModal
cancel-button-appearance="secondary"
:visible="modalVisible"
title="Modal"
@cancel="handleModalClose"
@proceed="handleModalProceed"
/>
cancelButtonDisabled
By default the cancel button is enabled, but you can pass true
to this prop should you want to change that.
<KModal
:cancel-button-disabled="false"
:visible="modalVisible"
title="Modal"
@cancel="handleModalClose"
@proceed="handleModalProceed"
/>
hideCancelButton
Use this prop to hide the cancel button. Defaults to false
.
<KModal
hide-cancel-button
:visible="modalVisible"
title="Modal"
@cancel="handleModalClose"
@proceed="handleModalProceed"
/>
hideCloseIcon
Prop that allows you to hide close icon next to the title. Defaults to false
. When no title is passed and hideCloseIcon
is true
, the modal header section will be hidden.
<KModal
hide-close-icon
:visible="modalVisible"
@cancel="handleModalClose"
@proceed="handleModalProceed"
>
Modal header section is omitted when no header content is present.
</KModal>
maxWidth
Max width of the modal. Defaults to 500px
.
<KModal
max-width="90%"
title="Modal"
:visible="modalVisible"
@cancel="handleModalClose"
@proceed="handleModalProceed"
/>
maxHeight
Maximum height of the content area. When content overflows, content area becomes scrollable. Default value is viewport height minus 200px
(calc(100vh - 200px)
).
<KModal
max-height="200px"
title="Modal"
:visible="modalVisible"
@cancel="handleModalClose"
@proceed="handleModalProceed"
>
<p>Lorem ipsum dolor sit amet...
</KModal>
zIndex
z-index
value for the modal. Defaults to 1100
.
<KModal
z-index="9999"
title="Modal"
:visible="modalVisible"
@cancel="handleModalClose"
@proceed="handleModalProceed"
/>
fullScreen
Use this prop to make modal window take up almost the whole screen. When set to true
, maxWidth
and maxHeight
props will have no effect.
<KModal
full-screen
title="Modal Full Screen"
:visible="modalVisible"
@cancel="handleModalClose"
@proceed="handleModalProceed"
/>
closeOnBackdropClick
Whether clicking on backdrop should close the modal (by emitting the cancel
event). Defaults to false
.
<KModal
:close-on-backdrop-click="false"
hide-close-icon
:visible="modalVisible"
@cancel="handleModalClose"
@proceed="handleModalProceed"
>
Try clicking on modal backdrop.
</KModal>
tabbableOptions
Options to be passed to focus-trap
, which is responsible for trapping focus inside the modal box.
inputAutofocus
Boolean to control whether KModal should set focus on the first visible input field as soon as modal opens. Defaults to false
.
<KModal
input-autofocus
title="Modal"
:visible="modalVisible"
@cancel="handleModalClose"
@proceed="handleModalProceed"
>
<KInput
label="Slotted input"
:label-attributes="{ info: 'Focus trap set focus on this input field for you as soon as modal opened.' }"
required
/>
</KModal>
NOTE
Sometimes you may need to asynchronously fetch data before displaying the form inside a modal. In that case, you can bind inputAutofocus
to your local loading state variable in order to set inputAutofocus
prop to true
as soon as content loads so that KModal could set focus on input fields as soon as they are available.
<template>
<KModal
:input-autofocus="!loading"
title="Modal"
:visible="modalVisible"
@cancel="handleModalClose"
@proceed="handleModalProceed"
>
<KInput
v-if="!loading"
label="Slotted input"
:label-attributes="{ info: 'Focus trap set focus on this input field for you as soon as it became available.' }"
required
/>
<ProgressIcon v-else />
</KModal>
</template>
<script setup lang="ts">
const modalVisible = ref<boolean>(false)
const loading = ref<boolean>(true)
watch(modalVisible, (newValue): void => {
if (newValue) {
setTimeout(() => {
loading.value = false
}, 3000)
} else {
loading.value = true
}
})
</script>
Slots
default
Slot for modal content. Not to be confused with the content
slot which takes presense over all other slots when provided.
<KModal
title="Modal"
:visible="modalVisible"
@cancel="handleModalClose"
@proceed="handleModalProceed"
>
<p>Lorem ipsum dolor sit amet...
</KModal>
title
Slot for title string.
<KModal
title="Title"
:visible="modalVisible"
@cancel="handleModalClose"
@proceed="handleModalProceed"
>
<template #title>
Slotted title
</template>
</KModal>
footer
Slot for footer content.
<KModal
title="Title"
:visible="modalVisible"
@cancel="handleModalClose"
@proceed="handleModalProceed"
>
<template #footer>
All prices are in USD.
</template>
</KModal>
footer-actions
Use this slot should you need to provide cusom buttons in modal footer. Ommited when footer
slot is used.
<template>
<KModal
:visible="modalVisible"
title="Modal"
@cancel="handleModalClose"
@proceed="handleModalProceed"
>
<template #footer-actions>
<KButton
appearance="tertiary"
@click="handleModalClose">
<BackIcon />
Back
</KButton>
<KButton @click="handleModalClose">
Proceed
<ForwardIcon />
</KButton>
</template>
</KModal>
</template>
<script setup lang="ts">
const modalVisible = ref<boolean>(false)
const handleModalClose = () => {
modalVisible.value = false
}
</script>
NOTE
KModal takes care of placement and spacing between the buttons when using footer-actions
slot. However, should you want to mimic that container behaviour using, for example, footer
slot, we recomend you use kui-space-40
design token or 8px
for spacing between the buttons and place the container containing the buttons on the right using margin-left: auto;
rule.
content
By default KModal provides you with the standard layout: modal header (optional), content section and footer. However, should you need to make a custom modal, you can use content
slot for your content. It will provide you with just a wrapper container with white background.
IMPORTANT
Focus-trap requires at least one tabbable element to be present in modal at all times. You can learn more about what elements are considered tabbable here. Make sure your modal has at least one element with non-negative tabindex
attribute (for example close icon with role="button"
and tabindex="0"
attributes).
<template>
<KModal :visible="modalVisible" @proceed="handleModalProceed">
<template #content>
<div class="modal-content">
<img src="/img/gateway-manager.png" alt="Gateway Manager" />
<div class="info-container">
<h3>Welcome to Gateway Manager!</h3>
<p>Optimize Kong Gateway and Ingress Controller deployments across hybrid, multi-cloud, and Kubernetes environments. Get single-pane management, a 99.99% SLA, and seamless day-2 operations.</p>
<KButton @click="modalVisible = false">Show me around</KButton>
</div>
</div>
</template>
</KModal>
</template>
<script setup lang="ts">
const modalVisible = ref<boolean>(false)
</script>
<style lang="scss" scoped>
.modal-content {
img {
border-top-left-radius: $kui-border-radius-40;
border-top-right-radius: $kui-border-radius-40;
}
.info-container {
display: flex;
flex-direction: column;
gap: $kui-space-60;
padding: $kui-space-80;
text-align: center;
p {
color: $kui-color-text-neutral;
}
}
}
</style>
NOTE
By default when using content
slot KModal comes with a wrapper container with no padding. However, should you want to customize that behaviour, we suggest you use kui-space-80
design token or 24px
for any container padding and kui-border-radius-40
token or 8px
for rounding the corners.
Events
proceed
Emitted when action button is clicked.
cancel
Emitted when cancel button or close icon (when not hidden) is clicked.