vwf .

Developer Docs

Quick reference guides with props tables, usage examples, and best practices for rapid development

Components/Docs/ConfirmModal

ConfirmModal

ConfirmModal

A styled confirmation dialog that replaces browser's native confirm(). Provides two usage patterns: Component pattern for full state control, and Promise pattern for simple async/await workflows.

Quick Example

Danger

Async/Await

🔧 Props

Complete configuration options for ConfirmModal component and showConfirm function.

PropTypeDefaultDescription
isOpenvan.State<boolean>falseWhether the modal is visible (use van.state for reactivity)
titlestring'Confirm Action'Modal title text
messagestring'Are you sure?'Confirmation message body
confirmTextstring | () => string'Confirm'Confirm button text (can be reactive function for loading states)
cancelTextstring'Cancel'Cancel button text
variantstring'danger'Visual variant: 'danger', 'warning', 'info'
onConfirmFunctionundefinedCallback when user confirms
onCancelFunctionundefinedCallback when user cancels or closes

💻 Component Pattern

Use when you need full control over modal state and loading states:

Basic Usage

const showModal = van.state(false);

Button({
  onclick: () => showModal.val = true
}, 'Delete Item'),

() => showModal.val ? ConfirmModal({
  isOpen: showModal,
  title: 'Delete Item',
  message: 'This action cannot be undone.',
  variant: 'danger',
  onConfirm: () => {
    deleteItem();
    showModal.val = false;
  },
  onCancel: () => showModal.val = false
}) : ''

With Loading State

const showModal = van.state(false);
const isDeleting = van.state(false);

const handleDelete = async () => {
  isDeleting.val = true;
  await deleteItem();
  isDeleting.val = false;
  showModal.val = false;
  showToast('Deleted successfully', 'success');
};

ConfirmModal({
  isOpen: showModal,
  title: 'Delete Service',
  message: 'This will permanently delete the service.',
  confirmText: () => isDeleting.val ? 'Deleting...' : 'Delete',
  variant: 'danger',
  onConfirm: handleDelete,
  onCancel: () => showModal.val = false
})

🔮 Promise Pattern (showConfirm)

Use for simple async/await workflows without managing state:

Basic Usage

import { showConfirm } from 'shared-components/ui/ConfirmModal.js';

const handleDelete = async () => {
  const confirmed = await showConfirm({
    title: 'Delete Service',
    message: 'Are you sure?',
    variant: 'danger'
  });

  if (confirmed) {
    await deleteService();
    showToast('Deleted', 'success');
  }
};

With Custom Text

const confirmed = await showConfirm({
  title: 'Leave Page',
  message: 'You have unsaved changes. Leave anyway?',
  confirmText: 'Leave',
  cancelText: 'Stay',
  variant: 'warning'
});

Promise Pattern Config

PropTypeDefaultDescription
titlestring'Confirm Action'Modal title
messagestring'Are you sure?'Message body
confirmTextstring'Confirm'Confirm button text
cancelTextstring'Cancel'Cancel button text
variantstring'danger''danger', 'warning', or 'info'

Returns: Promise<boolean> - Resolves to true if confirmed, false if cancelled

🎨 Variants

Three semantic variants for different confirmation scenarios with automatic icons and colors.

Danger (Default)

For destructive, irreversible actions (delete, remove, destroy)

ConfirmModal({
  variant: 'danger',
  title: 'Delete Account',
  message: 'This action cannot be undone.'
})

Warning

For reversible but significant actions (cancel subscription, leave page)

ConfirmModal({
  variant: 'warning',
  title: 'Leave Page',
  message: 'You have unsaved changes.'
})

Info

For neutral confirmations (mark as read, enable feature)

ConfirmModal({
  variant: 'info',
  title: 'Enable Notifications',
  message: 'Would you like to receive updates?'
})

⚡️ Best Practices

✓ Do This

✓Use "danger" for Irreversible Actions

- Apply danger variant for deletions and permanent destructive actions

✓Use "warning" for Reversible Actions

- Use warning variant for actions that can be undone or reverted

✓Use Promise Pattern for Simple Workflows

- Leverage Promise-based showConfirm for clean async/await confirmation flows

✓Use Component Pattern for Loading States

- Use ConfirmModal component directly when you need loading states and state control

✓Show Loading States

- Display loading feedback during async operations for better UX

✓Use Descriptive Confirm Text

- Use specific button text like "Delete Account" instead of generic "OK"

✓Close Modal After Action

- Always close the modal after successful action completion

✗ Avoid This

✗Don't Overuse Confirmations

- Avoid showing confirmations for every action; causes confirmation fatigue

✗Don't Write Vague Messages

- Never use generic messages like "Are you sure?"; be specific about what will happen

✗Don't Forget to Close Modal

- Always close the modal after action; leaving it open confuses users

✗Don't Mix Patterns

- Choose either Component or Promise pattern; don't mix both in same flow

✗Don't Use Generic Button Text

- Avoid generic "OK" button text; use action-specific labels

✗Don't Skip Loading States

- Always show loading feedback for operations that take time

✗Don't Misuse Variants

- Never use info variant for dangerous destructive actions; use danger instead

🤔 When to Use Each Pattern

Use Component Pattern When:

✓You need loading states (button shows "Deleting...")

✓You need custom state management

✓You need to disable buttons during async operations

✓You need reactive button text

✓The modal is part of a larger component with complex state

Use Promise Pattern When:

✓You need simple yes/no confirmation

✓You want clean async/await code

✓You don't need loading states

✓Action completes quickly

✓You want minimal code

✨ Key Features

⭑Three Semantic Variants

- Danger, warning, and info variants with automatic icons and semantic colors

⭑Two Usage Patterns

- Component pattern for state control, Promise pattern for simple async/await workflows

⭑Loading State Support

- Reactive button text for async operations ("Deleting...", "Processing...")

⭑Full Accessibility

- Built on Modal component with keyboard navigation, focus management, and ARIA support

⭑Auto Cleanup

- Promise pattern automatically removes DOM elements after animation completes

⭑Glass Morphism Design

- Inherits Modal styling with glass effect, backdrop blur, and smooth animations

⭑Customizable Button Text

- Configure confirmText and cancelText for action-specific button labels

⭑Automatic Icon Selection

- Icons automatically match variant (trash for danger, warning triangle, info circle)

💡 Common Use Cases

Real-world examples showing both Component and Promise patterns for common confirmation scenarios.

1. Delete Confirmation

const handleDelete = async () => {
  const confirmed = await showConfirm({
    title: 'Delete Service',
    message: 'This will permanently delete the service and all its data.',
    confirmText: 'Delete Service',
    variant: 'danger'
  });

  if (confirmed) {
    await deleteService(serviceId);
    showToast('Service deleted', 'success');
    router.navigate('/services');
  }
};

2. Leave Page with Unsaved Changes

const handleLeave = async () => {
  if (hasUnsavedChanges.val) {
    const confirmed = await showConfirm({
      title: 'Leave Page',
      message: 'You have unsaved changes. Leave anyway?',
      confirmText: 'Leave',
      cancelText: 'Stay',
      variant: 'warning'
    });

    if (!confirmed) return;
  }

  router.navigate('/dashboard');
};

3. Deactivate Account

const showDeactivateModal = van.state(false);
const isDeactivating = van.state(false);

const handleDeactivate = async () => {
  isDeactivating.val = true;
  await deactivateAccount();
  isDeactivating.val = false;
  showDeactivateModal.val = false;
  showToast('Account deactivated', 'success');
  router.navigate('/goodbye');
};

ConfirmModal({
  isOpen: showDeactivateModal,
  title: 'Deactivate Account',
  message: 'Your account will be deactivated. You can reactivate it anytime.',
  confirmText: () => isDeactivating.val ? 'Deactivating...' : 'Deactivate',
  variant: 'warning',
  onConfirm: handleDeactivate,
  onCancel: () => showDeactivateModal.val = false
})

4. Bulk Actions

const handleBulkDelete = async () => {
  const count = selectedItems.val.length;

  const confirmed = await showConfirm({
    title: `Delete ${count} Items`,
    message: `This will permanently delete ${count} selected items.`,
    confirmText: `Delete ${count} Items`,
    variant: 'danger'
  });

  if (confirmed) {
    await bulkDelete(selectedItems.val);
    showToast(`${count} items deleted`, 'success');
    selectedItems.val = [];
  }
};

5. Enable Feature

const handleEnableNotifications = async () => {
  const confirmed = await showConfirm({
    title: 'Enable Notifications',
    message: 'Get notified about new services and updates in your area.',
    confirmText: 'Enable',
    cancelText: 'Not Now',
    variant: 'info'
  });

  if (confirmed) {
    await enableNotifications();
    showToast('Notifications enabled', 'success');
  }
};

🔗 Integration Patterns

Best practices for integrating ConfirmModal with other components and application patterns.

With Toast (Feedback)

const handleDelete = async () => {
  const confirmed = await showConfirm({
    title: 'Delete Item',
    message: 'Are you sure?',
    variant: 'danger'
  });

  if (confirmed) {
    await deleteItem();
    showToast('Item deleted successfully', 'success');
  } else {
    showToast('Deletion cancelled', 'info');
  }
};

With Router (Navigation)

const handleLogout = async () => {
  const confirmed = await showConfirm({
    title: 'Logout',
    message: 'Are you sure you want to logout?',
    variant: 'info'
  });

  if (confirmed) {
    await logout();
    router.navigate('/auth/signin');
  }
};

With Forms (Discard Changes)

const handleCancel = async () => {
  if (form.isDirty.val) {
    const confirmed = await showConfirm({
      title: 'Discard Changes',
      message: 'You have unsaved changes. Discard them?',
      confirmText: 'Discard',
      cancelText: 'Keep Editing',
      variant: 'warning'
    });

    if (!confirmed) return;
  }

  router.navigate('/services');
};

Explore More Components

Browse other component categories