Skip to content

Modal

A modal can be used in a variaty of ways. It can be used to display a message to the user, ask for a confirmation or to display a form. The appropriate type can be set with the type property.

Example Usage

Example

vue
<template>
  <SkButton class="mr-s mb-s" @click="modal.open()">Open Alert</SkButton>
  <SkButton class="mr-s mb-s" @click="modal2.open()">Async Confirm</SkButton>
  <SkButton class="mr-s mb-s" @click="programmaticConfirm()">Programmatic Confirm</SkButton>
  <SkButton class="mr-s mb-s" @click="programmaticPrompt()">Programmatic Prompt</SkButton>

  <SkModal
    ref="modal"
    type="alert"
    title="Ich bin ein einfaches Modal"
    description="Das ist meine Beschreibung. "
    action-text="Ok, verstanden"
    class="bg-orange"
  />

  <SkModal
    ref="modal2"
    type="confirm"
    title="Möchtest du wirklich löschen?"
    action-text="Löschen"
    :action="deleteDummyItem"
  >
    <h1>Wirklich löschen?</h1>
    <p>Das kann nicht rückgängig gemacht werden.</p>

    <template #footer="{ action, close, loading }">
      <SkButton type="secondary" @click="close()">Abbrechen</SkButton>
      <SkButton v-if="!loading" type="primary" @click="action()">Löschen</SkButton>
      <SkButton v-else type="primary" :loading="true">Löschen...</SkButton>
    </template>
  </SkModal>
</template>

<script setup>
import { onMounted, ref } from 'vue';
// import { useModal } from '@/composables';
const modal = ref(undefined);
const modal2 = ref(undefined);

// const { createModal } = useModal();
let createModal = undefined;
async function deleteDummyItem() {
  const prom = new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5 ? resolve() : reject('This is an error');
    }, 1000);
  });
  await prom;
}

// this is only neccessary for server side rendering
onMounted(async () => {
  const { useModal } = await import('my-lib/composables');
  createModal = useModal().createModal;
});

// two different usecases
async function programmaticPrompt() {
  const modal3 = await createModal({
    title: 'Vergib einen Namen',
    description: 'Wie soll die Serie heißen?',
    actionText: 'Speichern',
    type: 'prompt',
  });
  const result = await modal3.open();
  alert(result);
}

async function programmaticConfirm() {
  const modal4 = await createModal({
    title: 'Element wirklich löschen?',
    description: 'Dies kann nicht rückgängig gemacht werden.',
    actionText: 'Löschen',
    type: 'confirm',
  });
  modal4.action(async () => {
    await deleteDummyItem();
  });
  modal4.open();
}
</script>

Composable

You can use the useModal composable to create a modal instance. This can be used to open and close the modal programmatically.

vue
<script setup>
import { useModal } from '@/composables';
const { createModal } = useModal();

async function programmaticConfirm() {
  const modal4 = await createModal({
    title: 'Element wirklich löschen?',
    // ... other component props
  })
    .action(async () => {
      // some async action
    })
    .open();
}
</script>

Reference

Props

NameTypeDefaultDescription
typeString'confirm'Type of modal - 'alert', 'prompt' or 'confirm'
titleString'Are you sure?'Title text shown in modal
actionTextStringText for action button
actionFunctionCallback for action button
descriptionStringDescriptive text shown under title

Events

NameDescription
closeEmitted when modal closes
confirmEmitted when action is confirmed
errorEmitted on any error

Methods

MethodDescription
open()Open the modal
close()Close the modal
action()Set callback for action button, can be an async function to automaticly show loading state

Exposed

PropertyTypeDescription
loadingBooleanLoading state
elElementModal element reference

Slots

NameDescription
defaultDefault slot for modal content
footerFooter slot for action buttons

Slot Props

The footer slot is provided the following props:

PropTypeDescription
actionFunctionCall this prop to trigger the primary action
closeFunctionCall this prop to close the modal
loadingBooleanIndicates background action is in progress

For example:

<template #footer="{ action, close, loading }">
  <button :disabled="loading" @click="action">
    Confirm
  </button>
  <button @click="close">
    Cancel
  </button>
</template>

The default slot does not have any provided props. Any content can be passed to this slot, for example:

<template #default>
   <p>Custom modal content</p>
</template>