Skip to content

Modal ​

A general-purpose overlay panel for forms, details, and complex content. Supports draggable, fullscreen, drawer mode, custom transitions, stacked modals, focus trap, auto-close, programmatic API, and more.

vue
<script setup>
const show = ref(false)
</script>

<template>
  <button @click="show = true">Open Modal</button>
  <VxModal v-model="show" title="Basic Modal">
    <p>This is a basic modal.</p>
  </VxModal>
</template>

With Description ​

vue
<template>
  <VxModal v-model="show" title="Edit Profile" description="Make changes here." />
</template>

Sizes ​

vue
<template>
  <VxModal size="sm" />
  <VxModal size="md" />
  <VxModal size="lg" />
  <VxModal size="xl" />
  <VxModal size="full" />
</template>

Custom Width ​

Set an arbitrary width with the width prop.

vue
<template>
  <VxModal v-model="show" :width="666" title="Custom Width" />
  <VxModal v-model="show" width="80%" title="Percentage Width" />
</template>

Draggable ​

Drag the modal by its header to reposition it.

vue
<template>
  <VxModal v-model="show" title="Drag Me" draggable />
</template>

Fullscreen Toggle ​

A button in the header lets users expand the modal to fullscreen and back.

vue
<template>
  <VxModal v-model="show" title="Expand Me" fullscreenable />
</template>

Before Close ​

An async guard that runs before closing. Return false to prevent it.

vue
<script setup>
// Sync — native browser confirm
function beforeClose() {
  return window.confirm('Discard changes?')
}

// Async — with useConfirm dialog
import { useConfirm } from 'veloxui'
const dialog = useConfirm()

async function beforeCloseAsync() {
  // resolves = allow close, rejects = block close
  await dialog.warning({
    title: 'Discard Changes?',
    confirmText: 'Discard',
    cancelText: 'Keep Editing',
  })
}
</script>

<template>
  <VxModal v-model="show" :before-close="beforeClose" title="Guard" />
</template>

Drawer Mode ​

Slide in from any edge. Use the drawer prop with left, right, top, or bottom.

vue
<template>
  <VxModal v-model="show" drawer="left" title="Left" />
  <VxModal v-model="show" drawer="right" title="Right" />
  <VxModal v-model="show" drawer="top" title="Top" />
  <VxModal v-model="show" drawer="bottom" title="Bottom" />
  <VxModal v-model="show" drawer="right" size="lg" title="Wide Drawer" />
</template>

Custom Transitions ​

Choose an animation: zoom (default), fade, slide-up, slide-down, flip.

vue
<template>
  <VxModal transition="fade" />
  <VxModal transition="slide-up" />
  <VxModal transition="slide-down" />
  <VxModal transition="flip" />
</template>

Stacked Modals ​

Open modals on top of other modals. Each gets a higher z-index automatically.

vue
<template>
  <VxModal v-model="first" title="First">
    <template #footer>
      <button @click="second = true">Open Second</button>
    </template>
  </VxModal>
  <VxModal v-model="second" title="Second" />
</template>

Focus Trap ​

Enabled by default. Tab key cycles within the modal for accessibility.

vue
<template>
  <!-- Focus trap is enabled by default -->
  <VxModal v-model="show" title="Focus Trap">
    <input placeholder="Tab cycles here" />
  </VxModal>

  <!-- Disable it -->
  <VxModal v-model="show" :focus-trap="false" />
</template>

Auto Close ​

Automatically close after a duration (ms).

vue
<template>
  <VxModal v-model="show" :auto-close="3000" title="Closes in 3s" />
</template>

Destroy on Close ​

By default, content is destroyed when the modal closes (destroy-on-close). Set it to false to keep content alive (preserves form state, scroll position, etc).

vue
<template>
  <VxModal v-model="show" :destroy-on-close="false" title="Keep Alive" />
</template>

Persistent ​

Cannot be dismissed by overlay click or Escape. Shows a shake animation.

vue
<template>
  <VxModal v-model="show" persistent title="Persistent" />
</template>

Position ​

Place the modal at any corner or edge of the viewport.

vue
<template>
  <VxModal v-model="show" position="top-left" title="Top Left" />
  <VxModal v-model="show" position="top-center" title="Top Center" />
  <VxModal v-model="show" position="top-right" title="Top Right" />
  <VxModal v-model="show" position="center" title="Center (default)" />
  <VxModal v-model="show" position="bottom-left" title="Bottom Left" />
  <VxModal v-model="show" position="bottom-center" title="Bottom Center" />
  <VxModal v-model="show" position="bottom-right" title="Bottom Right" />
</template>

Centered vs Top ​

vue
<template>
  <VxModal v-model="show" :centered="false" title="Top" />
</template>

Hide Overlay ​

vue
<template>
  <VxModal v-model="show" hide-overlay />
</template>

Loading ​

vue
<template>
  <VxModal v-model="show" loading title="Processing..." />
</template>

Scrollable Content ​

vue
<template>
  <VxModal v-model="show" title="Terms" size="sm">
    <div v-for="i in 20" :key="i"><p>Long content...</p></div>
  </VxModal>
</template>
vue
<template>
  <VxModal v-model="show">
    <template #header>Custom header</template>
    <template #footer>
      <button @click="show = false">Cancel</button>
      <button @click="show = false">Confirm</button>
    </template>
  </VxModal>
</template>

Programmatic API ​

Use the useModal() composable to open modals from JavaScript without writing template markup.

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

const { open } = useModal()

function showModal() {
  const instance = open({
    title: 'Hello',
    content: 'Created from JavaScript!',
    size: 'sm',
  })

  // Close programmatically
  // instance.close()
}

function showDrawer() {
  open({
    title: 'Drawer',
    drawer: 'right',
    content: 'A programmatic drawer.',
    autoClose: 3000,
  })
}
</script>

Teleport Target ​

Mount the modal into a custom container instead of body.

vue
<template>
  <VxModal v-model="show" teleport-to="#my-container" />
</template>

Props ​

PropTypeDefaultDescription
modelValuebooleanfalseShow/hide (v-model)
titlestring''Header title
descriptionstring''Subtitle below title
size'sm' | 'md' | 'lg' | 'xl' | 'full''md'Modal width
widthstring | number—Custom width (overrides size)
closablebooleantrueShow close button
closeOnOverlaybooleantrueClose on overlay click
closeOnEscbooleantrueClose on Escape key
centeredbooleantrueVertically center
persistentbooleanfalseShake instead of close
hideOverlaybooleanfalseTransparent backdrop
loadingbooleanfalseShow loading overlay
draggablebooleanfalseDrag by header
fullscreenablebooleanfalseShow fullscreen toggle
beforeClose() => boolean | Promise<boolean>—Guard before closing
drawer'left' | 'right' | 'top' | 'bottom'—Drawer mode
transition'zoom' | 'fade' | 'slide-up' | 'slide-down' | 'flip'—Animation
focusTrapbooleantrueTrap Tab within modal
autoClosenumber0Auto-close after ms
destroyOnClosebooleantrueDestroy content on close
teleportTostring'body'Teleport target selector
position'center' | 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right''center'Modal position

Events ​

EventDescription
update:modelValueValue changed
closeClose triggered
openedEnter transition finished
closedLeave transition finished

Slots ​

SlotDescription
defaultBody content
headerCustom header
footerFooter actions (default: Close button)

Exposed Methods ​

MethodDescription
close()Close the modal programmatically
toggleFullscreen()Toggle fullscreen state