Content
Use the slot property to inject content into a Modal without detaching. Simply turn the card content into a local component and swap it out with the slot.
Modals are overlay components used for tasks or decisions that require user focus and confirmation. They block access to the main interface and should be used only for critical actions or information that cannot appear inline. When a modal appears, a background overlay using black at 25% opacity (RGBA 0,0,0,0.25) is applied.
For more information on ModelValues please have a look to the Vue's Data Binding section.
const modelValue = defineModel<boolean>('modelValue', {
required: true,
default: false,
});export interface ModalProps {
title?: string;
closeOnClick?: boolean;
size?: 'narrow' | 'wide';
closeButton?: boolean;
headingIcon?: IconName;
headerSize?: 'default' | 'tiny';
content?: string | (() => VNode) | (() => VNode[]);
infoText?: string;
actions?: (AppButtonProps & {
component?: 'AppButton',
text: string;
onClick: () => void;
} | Omit<LinkProps, 'to'> & {
component: 'Link',
to?: string;
text: string;
onClick: () => void;
})[];
}NOTE
Submit Event (@submit): Triggered when user clicks the default submit button or any other button who's onClick function calls the submit component method.
In general there are two different ways to use the Modal component. You have the option to define the entire modal in HTML only which is suitable for cases in which you only have few modals with static content inside of one component.
In those cases you pass everything via regular Vue props. This will demonstrate the actual implementation of this playground Modal.
<script lang="ts" setup>
const modalValue = ref(false);
</script>
<template>
<Modal
v-model="modelValue"
:actions="[
{
text: 'Link',
component: 'Link' as const,
type: 'primary' as NonNullable<LinkProps['type']>,
onClick: () => {
console.log('Cancel');
modalRef.value?.cancel();
},
},
{
text: 'Secondary',
secondary: true,
icon: 'close' as IconName,
onClick: () => {
console.log('Close');
modalRef.value?.cancel();
},
},
{
text: 'Primary',
icon: 'send' as IconName,
trailingIcon: true,
onClick: () => {
console.log('Send');
modalRef.value?.submit();
},
},
]"
// in the playground the icon is set dynamically based on your actual selection
:headingIcon="icon"
>
Here goes your main content of the Modal including everything you can render with native HTML
Including Forms, Inputs, Icons, ...
</Modal>
</template>Alternatively, if you need various Modals and/or need to pass content dynamically for another reason during runtime, it is recommended to use the built-in code control via componentRef. When doing so, it is strongly recommended that you define your actions to include one of the exposed util functions cancel or submit. For purposes that demand for dynamic and complex content rendering, vue's render function often is the best choice. Alternately you can also pass a simple string as content, if that is sufficient for your purpose.
A more complex example might look like this.
<script lang="ts" setup>
import { h } from 'vue';
const modelValue = ref(false);
const userName = ref('');
const modalRef = useTemplateRef<InstanceType<typeof Modal>>('modal');
const showModal = () => {
modalRef.value?.showModal({
title: 'Opened via code',
size: 'wide',
content: () => [
h(TextInput, {
label: 'User Name',
placeholder: 'Enter your user name',
modelValue: userName.value,
'onUpdate:modelValue': (value: string) => {
userName.value = value;
},
}),
h('div', { class: 'modal__content__user-name', style: { color: 'red' } }, userName.value)
],
closeButton: true,
headingIcon: 'ai' as IconName,
actions: [
{
text: 'Cancel',
component: 'AppButton',
secondary: true,
onClick: () => {
console.log('Cancel');
modalRef.value?.cancel();
},
},
{
text: 'Submit',
component: 'AppButton',
onClick: () => {
console.log('Submit');
modalRef.value?.submit();
},
},
]
});
};
</script>
<template>
<Modal ref="modal" v-model="modelValue" />
</template>You are surely free to combine those approaches, too. You could, for example, define different contents inside the default slot with conditional rendering based on different rendering modes.
<script setup lang="ts">
const renderingModes = ['form', 'dialog', 'delete-user'];
const activeMode = ref('form');
// ref setup like demonstrated in previous example
const showModal = (mode: string) => {
activeMode = mode;
modalRef.value?.showModal({
title: 'Opened via code',
size: 'wide',
closeButton: true,
headingIcon: 'ai' as IconName,
actions: [
{
text: 'Cancel',
component: 'AppButton',
secondary: true,
onClick: () => {
console.log('Cancel');
modalRef.value?.cancel();
},
},
{
text: 'Submit',
component: 'AppButton',
onClick: () => {
console.log('Submit');
modalRef.value?.submit();
},
},
]
})
}
</script>
<template>
<Modal v-model="openModal">
<div v-if="activeMode === 'form'">
<TextInput v-model ... />
...
<NumberInput ... />
</div>
<div v-if="activeMode === 'delete-user'">
<Logo :company="'pohlcon'" />
...
</div>
</Modal>--color-lila-95--color-lila-30--color-lila-20--color-lila-80--color-lila-54--color-grey-93--color-grey-90--color-grey-95--color-grey-98--color-transparent-0--color-grey-93--color-transparent-0--color-grey-95--color-red-95--color-grey-95--color-blue-95--color-green-95--color-ochre-95--color-lila-30--color-grey-98--color-grey-98--color-lila-30--color-lila-70--color-lila-30--color-lila-70--color-grey-40--color-grey-70--color-red-50--color-grey-40--color-blue-45--color-green-50--color-ochre-45--color-lila-70--color-grey-90--color-grey-86--color-grey-93--color-grey-90--color-red-70--color-azure-45--color-grey-70--color-blue-67--color-green-75--color-ochre-70--color-lila-30--color-lila-30--color-grey-98--color-grey-98--color-lila-30--color-lila-70--color-lila-30--color-lila-70--color-grey-40--color-grey-70--color-red-50--color-grey-40--color-blue-45--color-grey-98--color-grey-25--color-grey-40--color-green-50--color-grey-54--color-ochre-45export {
modal-color--color-grey-90--color-grey-25--color-grey-70Use the slot property to inject content into a Modal without detaching. Simply turn the card content into a local component and swap it out with the slot.
Show or hide a heading Icon
Show or hide a close button