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
With Header and Footer
<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 |
|---|---|---|---|
title | string | undefined | The title of the dialog. |
description | string | undefined | The description of the dialog. |
content | object | undefined | The content of the dialog. |
overlay | boolean | true | Render an overlay behind the dialog. |
scrollable | boolean | false | When true, enables scrollable overlay mode where content scrolls within the overlay. |
transition | boolean | true | Animate the dialog when opening or closing. |
fullscreen | boolean | false | When true, the dialog will take up the full screen. |
portal | string | boolean | HTMLElement | true | Render the dialog in a portal. |
close | boolean | Partial<ButtonProps> | true | Display a close button to dismiss the dialog. |
closeIcon | string | object | appConfig.ui.icons.close | The icon displayed in the close button. |
dismissible | boolean | true | When false, the dialog will not close when clicking outside or pressing escape. |
ui | object | undefined | UI customization options. |
open | boolean | undefined | The controlled open state of the dialog. Can be binded as v-model:open. |
defaultOpen | boolean | false | The open state of the dialog when it is initially rendered. |
modal | boolean | true | The modality of the dialog. |
scale | number | 0.96 | The scale factor for the entrance/exit animation. |
variants | object | {} | Custom animation variants for the dialog. |
transitionOptions | object | {} | Custom transition options for the dialog animation. |
Events
| Event | Payload | Description |
|---|---|---|
update:open | (open: boolean) => void | Emitted 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 |
|---|---|---|---|
ui | object | - | 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 |