Skip to content

Dialog ​

Диалог подтверждения/оповещения для принятия решений пользователем. Используйте компонент шаблона VxDialog, программный composable useConfirm() или сочетайте с VxModal для многошаговых мастеров.

Stepped Dialog ​

Многошаговый мастер на базе VxModal с навигацией Previous / Next и финальной кнопкой Save.

Full Example Code
vue
<script setup>
import { ref, computed } from 'vue'

const show = ref(false)
const step = ref(0)
const saving = ref(false)
const form = ref({
  name: '',
  email: '',
  notifications: true,
  theme: 'system',
  agree: false,
})

const steps = [
  { title: 'Account', desc: 'Basic information' },
  { title: 'Preferences', desc: 'Customize experience' },
  { title: 'Confirm', desc: 'Review & save' },
]

const isFirst = computed(() => step.value === 0)
const isLast = computed(() => step.value === steps.length - 1)

function open() {
  step.value = 0
  form.value = { name: '', email: '', notifications: true, theme: 'system', agree: false }
  saving.value = false
  show.value = true
}
function next() { if (!isLast.value) step.value++ }
function prev() { if (!isFirst.value) step.value-- }
function save() {
  saving.value = true
  setTimeout(() => {
    saving.value = false
    show.value = false
    // submit form.value to API...
  }, 1500)
}
</script>

<template>
  <button @click="open">Open Wizard</button>

  <VxModal v-model="show" size="sm" persistent :closable="false">
    <!-- Header with step indicator -->
    <template #header>
      <div style="width: 100%">
        <div style="display: flex; justify-content: space-between; margin-bottom: 16px">
          <h3>Create Account</h3>
          <span>Step {{ step + 1 }} of {{ steps.length }}</span>
        </div>
        <div class="wiz-steps">
          <div
            v-for="(s, i) in steps" :key="i"
            class="wiz-step"
            :class="{ 'wiz-step--active': i === step, 'wiz-step--done': i < step }"
          >
            <div class="wiz-dot">
              <svg v-if="i < step" width="12" height="12" viewBox="0 0 24 24"
                fill="none" stroke="currentColor" stroke-width="2.5"
                stroke-linecap="round" stroke-linejoin="round">
                <path d="M5 12l5 5L20 7" />
              </svg>
              <span v-else>{{ i + 1 }}</span>
            </div>
            <div class="wiz-label">
              <div class="wiz-label-title">{{ s.title }}</div>
              <div class="wiz-label-desc">{{ s.desc }}</div>
            </div>
          </div>
        </div>
      </div>
    </template>

    <!-- Step content with slide transition -->
    <Transition name="wiz-fade" mode="out-in">
      <!-- Step 1: Account -->
      <div v-if="step === 0" key="s0" class="wiz-body">
        <label class="wiz-field">
          <span class="wiz-field-label">Full Name</span>
          <input v-model="form.name" placeholder="John Doe" class="wiz-input" />
        </label>
        <label class="wiz-field">
          <span class="wiz-field-label">Email</span>
          <input v-model="form.email" type="email" placeholder="john@example.com"
            class="wiz-input" />
        </label>
      </div>

      <!-- Step 2: Preferences -->
      <div v-else-if="step === 1" key="s1" class="wiz-body">
        <label class="wiz-field wiz-field--row">
          <span class="wiz-field-label">Email notifications</span>
          <VxSwitch v-model="form.notifications" />
        </label>
        <div class="wiz-field">
          <span class="wiz-field-label">Theme</span>
          <div class="wiz-radios">
            <label class="wiz-radio"
              :class="{ 'wiz-radio--active': form.theme === 'light' }">
              <input v-model="form.theme" type="radio" value="light" /> Light
            </label>
            <label class="wiz-radio"
              :class="{ 'wiz-radio--active': form.theme === 'dark' }">
              <input v-model="form.theme" type="radio" value="dark" /> Dark
            </label>
            <label class="wiz-radio"
              :class="{ 'wiz-radio--active': form.theme === 'system' }">
              <input v-model="form.theme" type="radio" value="system" /> System
            </label>
          </div>
        </div>
      </div>

      <!-- Step 3: Review & Confirm -->
      <div v-else key="s2" class="wiz-body">
        <div class="wiz-review">
          <div class="wiz-review-row">
            <span class="wiz-review-label">Name</span>
            <span class="wiz-review-value">{{ form.name || '—' }}</span>
          </div>
          <div class="wiz-review-row">
            <span class="wiz-review-label">Email</span>
            <span class="wiz-review-value">{{ form.email || '—' }}</span>
          </div>
          <div class="wiz-review-row">
            <span class="wiz-review-label">Notifications</span>
            <span class="wiz-review-value">{{ form.notifications ? 'On' : 'Off' }}</span>
          </div>
          <div class="wiz-review-row">
            <span class="wiz-review-label">Theme</span>
            <span class="wiz-review-value">{{ form.theme }}</span>
          </div>
        </div>
        <label class="wiz-field wiz-field--row" style="margin-top: 12px">
          <input v-model="form.agree" type="checkbox" />
          <span>I agree to the Terms and Privacy Policy</span>
        </label>
      </div>
    </Transition>

    <!-- Footer: Previous / Next / Save -->
    <template #footer>
      <button v-if="isFirst" class="wiz-btn wiz-btn--ghost" @click="show = false">
        Cancel
      </button>
      <button v-else class="wiz-btn wiz-btn--ghost" @click="prev">
        ← Previous
      </button>

      <button v-if="!isLast" class="wiz-btn wiz-btn--primary" @click="next">
        Next →
      </button>
      <button v-else class="wiz-btn wiz-btn--save"
        :disabled="!form.agree || saving" @click="save">
        {{ saving ? 'Saving...' : 'Save Account' }}
      </button>
    </template>
  </VxModal>
</template>

Programmatic API (useConfirm) ​

Вызывайте из <script setup> — шаблон не нужен. Возвращает Promise, который резолвится при подтверждении и реджектится при отмене.

vue
<script setup>
import { useConfirm } from 'veloxui'

const confirm = useConfirm()

// Basic — string shorthand
function deleteItem() {
  confirm('Are you sure?')
    .then(() => {
      // confirmed
      console.log('Deleted!')
    })
    .catch(() => {
      // cancelled
      console.log('Cancelled')
    })
}

// Typed shorthand — .danger(), .success(), .warning(), .info()
function deleteAccount() {
  confirm.danger({
    title: 'Delete Account',
    description: 'This cannot be undone.',
    confirmText: 'Delete',
  }).then(() => {
    api.deleteAccount()
  })
}

// Async / await
async function removeMember() {
  try {
    await confirm.danger({
      title: 'Remove Member',
      description: 'They will lose access.',
      confirmText: 'Remove',
    })
    await api.removeMember(id)
  } catch {
    // user cancelled
  }
}

// Info alert (no cancel button)
function showAlert() {
  confirm.info({
    title: 'Update Available',
    confirmText: 'OK',
    showCancel: false,
  }).then(() => { ... })
}
</script>

Template Component ​

Для случаев, когда нужны slot-ы или реактивное состояние loading.

Types ​

vue
<template>
  <VxDialog type="info" title="Info" description="Saved." />
  <VxDialog type="success" title="Success" confirm-text="Great!" :show-cancel="false" />
  <VxDialog type="warning" title="Unsaved Changes" confirm-text="Leave" cancel-text="Stay" />
  <VxDialog type="danger" title="Delete" confirm-text="Delete" />
</template>

Without Icon ​

vue
<template>
  <VxDialog :icon="false" title="Confirm" />
</template>

Confirm Only ​

vue
<template>
  <VxDialog type="success" confirm-text="OK" :show-cancel="false" />
</template>

Closable ​

vue
<template>
  <VxDialog closable title="Notice" />
</template>

Loading ​

vue
<template>
  <VxDialog type="danger" :loading="isDeleting" @confirm="handleDelete" />
</template>

Custom Button Text ​

vue
<template>
  <VxDialog confirm-text="Discard" cancel-text="Keep" />
</template>

Custom Content ​

vue
<template>
  <VxDialog v-model="show" title="Rate Limit">
    <p>Custom HTML in the default slot.</p>
  </VxDialog>
</template>

Persistent ​

vue
<template>
  <VxDialog :persistent="false" close-on-overlay />
</template>

Sizes ​

vue
<template>
  <VxDialog size="sm" />
  <VxDialog size="md" />
  <VxDialog size="lg" />
</template>

Position ​

vue
<template>
  <VxDialog position="top-left" />
  <VxDialog position="top-center" />
  <VxDialog position="top-right" />
  <VxDialog position="center" />  <!-- default -->
  <VxDialog position="bottom-left" />
  <VxDialog position="bottom-center" />
  <VxDialog position="bottom-right" />
</template>

Props ​

PropTypeDefaultDescription
modelValuebooleanfalseПоказать/скрыть (v-model)
titlestring''Заголовок диалога
descriptionstring''Описание
type'info' | 'success' | 'warning' | 'danger''info'Иконка и цвет кнопки
size'sm' | 'md' | 'lg''sm'Ширина диалога
iconbooleantrueПоказывать иконку типа
closablebooleanfalseПоказывать кнопку закрытия
closeOnOverlaybooleanfalseЗакрывать по клику на оверлей
closeOnEscbooleantrueЗакрывать по Escape
confirmTextstring'Confirm'Текст кнопки подтверждения
cancelTextstring'Cancel'Текст кнопки отмены
showCancelbooleantrueПоказывать кнопку отмены
loadingbooleanfalseСостояние загрузки
persistentbooleantrueВстряхивать при клике на оверлей
position'center' | 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right''center'Позиция диалога

Events ​

EventDescription
update:modelValueЗначение изменилось
confirmНажата кнопка подтверждения
cancelНажата кнопка отмены
closeДиалог закрыт
openedАнимация открытия завершена
closedАнимация закрытия завершена

Slots ​

SlotDescription
defaultПользовательское содержимое тела (заменяет description)

useConfirm API ​

ts
import { useConfirm } from 'veloxui'

const confirm = useConfirm()

// Returns Promise<void>
// Resolves on confirm, rejects on cancel
confirm(options: ConfirmOptions | string): Promise<void>

// Type shortcuts
confirm.info(options)
confirm.success(options)
confirm.warning(options)
confirm.danger(options)

ConfirmOptions ​

OptionTypeDefaultDescription
titlestring''Заголовок диалога
descriptionstring''Описание
type'info' | 'success' | 'warning' | 'danger''info'Тип диалога
size'sm' | 'md' | 'lg''sm'Ширина диалога
iconbooleantrueПоказывать иконку
closablebooleanfalseПоказывать кнопку закрытия
confirmTextstring'Confirm'Кнопка подтверждения
cancelTextstring'Cancel'Кнопка отмены
showCancelbooleantrueПоказывать отмену
persistentbooleantrueВстряхивать при клике на подложку