Teleport renders component content outside current DOM hierarchy, essential for modals to avoid CSS stacking issues. Basic implementation:
Vue.js Dialogs Modals FAQ & Answers
18 expert Vue.js Dialogs Modals answers researched from official documentation. Every answer cites authoritative sources you can verify.
unknown
18 questionsAccessible confirmation dialogs must support standard keyboard shortcuts per WCAG 2.1 guidelines. Required shortcuts: (1) Escape key: close dialog (most critical), (2) Tab/Shift+Tab: cycle focus within dialog (focus trap), (3) Enter key: activate focused button (typically 'Confirm'), (4) Space key: activate focused button. Implementation with Vue 3 Composition API: onMounted(() => { window.addEventListener('keydown', handleKeydown); }); onUnmounted(() => { window.removeEventListener('keydown', handleKeydown); }); const handleKeydown = (e: KeyboardEvent) => { if (e.key === 'Escape') close(false); if (e.key === 'Enter' && focusedElement === confirmButton) confirm(); }. Best practices: (1) Focus 'Cancel' button by default (safer, prevents accidental confirmation), (2) Highlight focused button visibly (outline, background color), (3) Arrow keys for button navigation (left/right). Avoid: requiring mouse for any action, keyboard traps user cannot escape, no visible focus indicators.
Z-index stacking context determines layering order of positioned elements. New stacking contexts created by: position (absolute/relative/fixed) + z-index, transform, opacity < 1, filter, will-change. Problem: z-index only works within same stacking context, child with z-index: 9999 cannot appear above parent's sibling with z-index: 2. Modal solution: use Teleport to move modal outside parent stacking contexts:
Custom dialogs provide superior UX and functionality over native alert(). Key benefits: (1) Non-blocking: native alert() blocks JavaScript execution and UI rendering, custom dialogs use async/await without blocking, (2) Customizable: full control over styling, branding, animations, layout vs fixed browser chrome, (3) Accessibility: add ARIA attributes, focus management, keyboard navigation, screen reader support, (4) Rich content: include forms, images, complex HTML vs plain text only, (5) Consistent UX: same look across all browsers/OS vs native browser styling, (6) Better mobile experience: responsive design, touch-friendly buttons vs tiny native buttons, (7) Testable: easy to unit test custom components vs difficulty testing native alerts. Technical advantages: promise-based API (cleaner code), can programmatically close, support multiple simultaneous dialogs, integrate with state management (Pinia/Vuex). Native alert() only acceptable for quick debugging, never production code.
Use Vue 3 Composition API with onMounted/onUnmounted for proper event listener cleanup. Pattern: onMounted(() => { window.addEventListener('keydown', handleKeydown); }); onUnmounted(() => { window.removeEventListener('keydown', handleKeydown); }); const handleKeydown = (e: KeyboardEvent) => { if (e.key === 'Escape') close(); }. Key modifiers in templates: @keydown.enter="submit", @keydown.esc="close", @keydown.ctrl.s.prevent="save" (Ctrl+S). System modifiers: .ctrl, .alt, .shift, .meta (Cmd on Mac). Exact modifier: @keydown.ctrl.exact prevents trigger when other keys pressed. VueUse composables: import { onKeyStroke } from '@vueuse/core'; onKeyStroke('Escape', () => close()); automatically handles cleanup. Global vs component listeners: window.addEventListener for app-wide shortcuts, @keydown on specific elements for component-scoped. Performance: use event.key (modern) not event.keyCode (deprecated). Prevent default: e.preventDefault() stops browser default behavior. Best practice: always remove listeners in onUnmounted to prevent memory leaks.
defineProps and defineEmits provide cleaner syntax and better TypeScript support in . Parent usage:
Implement dialog queue system to prevent multiple overlapping modals. Strategy 1: Single dialog instance with queue. Use reactive queue: const dialogQueue = ref<DialogConfig[]>([]); const currentDialog = computed(() => dialogQueue.value[0]); function openDialog(config) { dialogQueue.value.push(config); } function closeDialog() { dialogQueue.value.shift(); }. Only render when currentDialog exists. Strategy 2: Disable trigger buttons when dialog open. Track open state: const isDialogOpen = ref(false);
Props and slots serve different purposes in modal components. Props: pass configuration data (title, size, closable, variant), typically simple types (string, boolean, number). Example:
Always remove event listeners in onUnmounted hook to prevent memory leaks. Leak pattern: onMounted(() => { window.addEventListener('resize', handleResize); }); // LEAK! No cleanup. Fixed pattern: const handleResize = () => { /* logic */ }; onMounted(() => { window.addEventListener('resize', handleResize); }); onUnmounted(() => { window.removeEventListener('resize', handleResize); }); // Cleanup. Important: use same function reference in add/remove (avoid anonymous functions). Best solution: VueUse's useEventListener: import { useEventListener } from '@vueuse/core'; useEventListener(window, 'resize', handleResize); // Auto cleanup! Other leak sources: (1) Intervals: const id = setInterval(() => {}, 1000); onUnmounted(() => clearInterval(id)); (2) Timeouts: const id = setTimeout(() => {}, 1000); onUnmounted(() => clearTimeout(id)); (3) Third-party libraries: onUnmounted(() => { chart.destroy(); map.remove(); }). Detect leaks: Chrome DevTools → Memory → Take heap snapshot before/after component mount/unmount, check for detached DOM nodes. Production best practice: use VueUse composables which handle cleanup automatically.
Use