Interactive

Motion dialog

A modal dialog component with smooth animations powered by motion-v.

The AnimatedDialog component is a modal dialog that combines the functionality of Nuxt UI's UModal with smooth animations powered by motion-v. It provides an enhanced user experience with customizable entrance and exit animations.

Usage

<template>
  <div class="flex justify-center w-full h-full">
    <MAnimatedDialog>
      <UButton
        label="Open Dialog"
        color="primary"
      />

      <template #body>
        <div class="p-4">
          <h3 class="text-lg font-semibold mb-2">
            Motion dialog
          </h3>
          <p class="text-muted mb-4">
            This dialog opens with smooth motion-v animations.
          </p>
          <UButton
            label="Action"
            color="primary"
            variant="outline"
            size="sm"
          />
        </div>
      </template>
    </MAnimatedDialog>
  </div>
</template>

Examples

<template>
  <MAnimatedDialog
    title="Dialog with Header and Footer"
    description="This dialog has custom header and footer slots"
  >
    <UButton
      label="Open Complex Dialog"
      color="primary"
    />

    <template #body>
      <div class="p-4">
        <p>This is the main content of the dialog. It can contain any Vue components or HTML elements.</p>
        <div class="mt-4 p-4 bg-muted rounded">
          <p>You can include forms, images, or any other content here.</p>
        </div>
      </div>
    </template>

    <template #footer="{ close }">
      <div class="flex gap-2">
        <UButton
          label="Cancel"
          color="neutral"
          variant="outline"
          @click="close"
        />
        <UButton
          label="Confirm"
          color="primary"
          @click="close"
        />
      </div>
    </template>
  </MAnimatedDialog>
</template>

Animation

scale sets the size the dialog shrinks to on entry and exit, variants overrides the initial / animate / exit targets, and transitionOptions overrides the tween. Combine them for any entrance — here three presets swap between a scale, a slide and a springy pop.

<template>
  <div class="flex flex-col gap-4">
    <div class="flex flex-wrap gap-2">
      <UButton
        v-for="option in presets"
        :key="option.id"
        :label="option.label"
        size="sm"
        :color="preset === option.id ? 'primary' : 'neutral'"
        :variant="preset === option.id ? 'solid' : 'subtle'"
        @click="preset = option.id"
      />
    </div>

    <MAnimatedDialog
      :scale="active.scale"
      :variants="active.variants"
      :transition-options="active.transitionOptions"
      title="Animated dialog"
      :description="`Preset: ${active.label}`"
    >
      <UButton
        label="Open dialog"
        color="primary"
      />

      <template #body>
        <div class="p-4">
          <p class="text-muted">
            The dialog opens with the “{{ active.label }}” animation. Pick another
            preset above, then open it again.
          </p>
        </div>
      </template>
    </MAnimatedDialog>
  </div>
</template>

<script setup lang="ts">
const presets = [
  {
    id: 'scale',
    label: 'Scale',
    scale: 0.96,
    variants: undefined,
    transitionOptions: undefined,
  },
  {
    id: 'slide',
    label: 'Slide in',
    scale: 1,
    variants: {
      initial: { opacity: 0, x: 80 },
      animate: { opacity: 1, x: 0 },
      exit: { opacity: 0, x: 80 },
    },
    transitionOptions: { type: 'spring' as const, stiffness: 260, damping: 26 },
  },
  {
    id: 'pop',
    label: 'Pop',
    scale: 0.5,
    variants: undefined,
    transitionOptions: { type: 'spring' as const, stiffness: 320, damping: 18 },
  },
]

const preset = ref('scale')
const active = computed(() => presets.find(option => option.id === preset.value) ?? presets[0]!)
</script>

Customize

Customize

TitleMotion dialog
DescriptionThis dialog opens with smooth motion-v animations.
ContentEverything inside animates in sequence when the dialog mounts.
Overlay
Scrollable
Fullscreen
Portal
Close
Close Icon
Dismissible
Unmount On Hide
Open
Default Open
Modal
Scale0.96

Props

Prop Type Default Description
titlestringundefinedThe title of the dialog.
descriptionstringundefinedThe description of the dialog.
contentobjectundefinedThe content of the dialog.
overlaybooleantrueRender an overlay behind the dialog.
scrollablebooleanfalseWhen true, enables scrollable overlay mode where content scrolls within the overlay.
transitionbooleantrueAnimate the dialog when opening or closing.
fullscreenbooleanfalseWhen true, the dialog will take up the full screen.
portalstring | boolean | HTMLElementtrueRender the dialog in a portal.
closeboolean | Partial<ButtonProps>trueDisplay a close button to dismiss the dialog.
closeIconstring | objectappConfig.ui.icons.closeThe icon displayed in the close button.
dismissiblebooleantrueWhen false, the dialog will not close when clicking outside or pressing escape.
uiobjectundefinedUI customization options.
openbooleanundefinedThe controlled open state of the dialog. Can be binded as v-model:open.
defaultOpenbooleanfalseThe open state of the dialog when it is initially rendered.
modalbooleantrueThe modality of the dialog.
scalenumber0.96The scale factor for the entrance/exit animation.
variantsobject{}Custom animation variants for the dialog.
transitionOptionsobject{}Custom transition options for the dialog animation.

Events

Event Payload Description
update:open(open: boolean) => voidEmitted when the open state of the dialog changes.

Slots

Slot Props Description
default-The trigger element for the dialog.
body-The main content of the dialog.
header{ close: () => void }Custom header content. Provides a close function.
footer{ close: () => void }Custom footer content. Provides a close function.
title-Custom title content.
description-Custom description content.
close{ ui: object }Custom close button content.

UI

This component's theme exposes the slots below. Override any of them per instance with the ui prop, or app-wide under ui.animatedDialog in app.config.ts.

Prop Type Default Description
uiobject-Per-slot classes merged over the theme defaults.
Slot Props Description
root-
content-relative overflow-hidden backdrop-blur-sm outline-none focus:outline-none border-default bg-default text-default
contentInner-will-change-transform
body-flex-1 p-4 sm:p-6
footer-flex items-center gap-1.5 p-4 sm:px-6 border-t border-default
Copyright © 2026