Toggle Sidebar B
AppearanceLight & dark mode D

Responsive Dialog

Dialog on desktop, Drawer on mobile. Use this for almost every modal in the app. Reach for plain Dialog only for short confirmations that still look fine on a phone.

Default

Use the trigger slot for the opener, the default slot for the content. Open state is controlled with v-model:open.

Dark previewReplay preview

With form

Form pattern inside ResponsiveDialog: padding handled with a wrapper div, action buttons at the end.

Dark previewReplay preview

Prevent close

preventClose blocks overlay clicks and Escape. The close-prevented event lets you show a confirmation prompt.

Dark previewReplay preview

Anatomy

Import all parts and piece them together.

vue
<script setup>
import {
  ResponsiveDialog,
} from "@/components/ui/responsive-dialog";
</script>

<template>
  <ResponsiveDialog>
    <template #trigger />
    <template #sticky-header />
    <template #default />
    <template #sticky-footer />
  </ResponsiveDialog>
</template>

API Reference

ResponsiveDialog

PropTypeDefaultDescription
titlestring""Accessible name for the dialog, rendered visually hidden. Pass it even when the design has no visible heading.
descriptionstring""Accessible description, also rendered visually hidden.
openbooleanOpen state. Supports v-model:open.
isResponsivebooleantrueSet false to force the Drawer variant at every breakpoint.
dialogMaxWidthstring"400px"Max width of the desktop dialog.
dialogMaxHeightstring"calc(100% - 4rem)"Max height of the desktop dialog.
preventClosebooleanfalseBlock overlay click and Escape. Emits close-prevented.
virtualKeyboardbooleantrueLift the drawer clear of the software keyboard and scroll the focused field into view. Mobile branch only; the desktop dialog ignores it.
drawerCloseButtonbooleanfalseShow a close button on the mobile drawer (default is swipe only).
hideOverlaybooleanfalseHide the dark backdrop.
flushContentbooleanfalseRender the content without the ScrollArea wrapper.
overflowContentbooleantrueEnable overflow-y-auto on the mobile drawer body.
EventDescription
update:openFires when the open state changes.
close-preventedFires when the user tries to close with preventClose enabled.
SlotDescription
triggerThe opener button. Receives open from the scope.
defaultMain content. Receives data from the scope.
sticky-headerHeader that sticks to the top while scrolling.
sticky-footerFooter that sticks to the bottom while scrolling.

Accessibility

Keyboard shortcuts and ARIA behavior.

Shortcut Description
SpaceWhen focus is on the trigger, opens the dialog.
EnterWhen focus is on the trigger, opens the dialog.
TabMoves focus to the next focusable element inside the content.
Shift + TabMoves focus to the previous focusable element.
EscCloses the overlay and returns focus to the trigger.
  • Adapts to a Dialog on desktop and a Drawer on mobile, keeping the same accessibility contract.
  • Focus is trapped within the content while open and restored to the trigger on close.
  • Provide a title so screen readers can announce the dialog via aria-labelledby.