Skip to content
Docs version
@hungpvq/draggable@1.3.1@hungpvq/vue-draggable@1.3.1@hungpvq/react-draggable@1.3.1

DraggableModal

Overview

DraggableModal is a centered dialog with an optional mask overlay. The dialog can be dragged and resized inside the container and always stays on top of other draggable items (including drawer layout layers). When multiple modals are open, later-opened modals stack above earlier ones.

Props

PropDescriptionTypeRequiredDefault Value
idStable item id for store commands / remount.stringfalseauto UUID
titleTitle displayed in the modal header.stringfalse-
showControls the visibility of the modal.booleanfalsefalse
widthWidth of the modal.numberfalse480
heightHeight of the modal.numberfalse320
topDistance from the top of the container.numberfalse-
leftDistance from the left of the container.numberfalse-
bottomDistance from the bottom of the container.numberfalse-
rightDistance from the right of the container.numberfalse-
centerCenter the modal both horizontally and vertically.booleanfalsetrue
centerXCenter the modal horizontally.booleanfalsetrue
centerYCenter the modal vertically.booleanfalsetrue
maskShows the dimmed overlay behind the modal.booleanfalsetrue
maskClosableCloses the modal when the mask is clicked.booleanfalsetrue
draggableAllows dragging the modal by the header handle.booleanfalsetrue
resizableAllows resizing the modal.booleanfalsetrue
disabledHeaderHides the header section.booleanfalsefalse
disabledCloseHides the close button.booleanfalsefalse
highlightMsHow long highlight stays on (ms).numberfalse5000
containerIdID of the parent container (for teleporting).stringfalse-

Events

NameDescription
closeEmitted when the modal is closed. Payload: ()
update:showEmitted when the visibility changes. Payload: (value:boolean)
update:boundsEmitted on drag/resize stop. Payload: {x,y,width,height}

React: use onUpdateShow / onClose / onBoundsChange instead of Vue update:* / close events.

A11y: root uses role="dialog", aria-modal, Esc closes, focus moves into the dialog and Tab is trapped.

Slots

Header layout: [ pre-title ] [ title | after-title ] …… spacer …… [ extra-btn ]. Full contract: header-slots.md.

VueReactDescription
defaultchildrenContent of the modal.
pre-titlepreTitleBefore the title group.
titletitleTitle text or custom title node (ReactNode | string).
after-titleafterTitleImmediately after title (before spacer).
extra-btnextraBtnTrailing header actions after the spacer.

Usage

Vue

vue
<script setup lang="ts">
import { DraggableContainer, DraggableModal } from '@hungpvq/vue-draggable';
</script>

<template>
  <DraggableContainer>
    <DraggableModal title="Confirm" show :width="480" :height="280">
      <div style="padding: 12px">Modal content</div>
    </DraggableModal>
  </DraggableContainer>
</template>

React

tsx
import { useState } from 'react';
import { DraggableContainer, DraggableModal } from '@hungpvq/react-draggable';

export function Example() {
  const [show, setShow] = useState(true);
  return (
    <DraggableContainer>
      <DraggableModal
        title="Confirm"
        show={show}
        onUpdateShow={setShow}
        width={480}
        height={280}
      >
        <div style={{ padding: 12 }}>Modal content</div>
      </DraggableModal>
    </DraggableContainer>
  );
}

Accessibility

Modal dialog: aria-modal, Tab trap, Escape, focus restore, sibling inert. See a11y.md.