MessageBox

View source
A modal message dialog offering both declarative and programmatic usage.

Introduction

MMessageBox is a modal dialog component designed for important notifications or scenarios requiring explicit user confirmation. It offers alert and confirm modes, six built-in semantic types, and programmatic invocation via useMessageBox().

Built on Nuxt UI's Modal component

Usage

Place the trigger element in the default slot. The component internally manages the open state via UModal:

<template>
  <MMessageBox title="Save Changes" description="Click "Got it" to close the dialog.">
<UButton label="Open" />
</MMessageBox>
</template>

mode Mode

alert shows only a confirm button; confirm provides both cancel and confirm buttons, returning a boolean result:

<template>
  <MMessageBox mode="confirm">
    <UButton label="Open" color="neutral" variant="subtle" />
  </MMessageBox>
</template>

type Type

type affects the default icon and confirm button color, with six semantic values:

<template>
  <MMessageBox type="primary" mode="confirm">
    <UButton label="Open" color="neutral" variant="subtle" />
  </MMessageBox>
</template>

icon Icon

icon overrides the default icon from type. Pass any Iconify icon name:

<template>
  <MMessageBox icon="i-lucide-rocket">
    <UButton variant="soft" color="success" label="Deployment Complete" />
  </MMessageBox>
</template>

label Button Labels

alertConfirmLabel controls the alert mode button label. confirmLabel and cancelLabel override the two buttons in confirm mode respectively:

<template>
  <MMessageBox
    mode="confirm"
    alert-confirm-label="Acknowledged"
    confirm-label="I Agree"
    cancel-label="I Disagree"
  >
    <UButton variant="outline" label="Custom Labels" />
  </MMessageBox>
</template>

buttonProps Button Properties

confirmButton and cancelButton accept full ButtonProps, allowing customization of icon, color, variant, and label:

<template>
  <MMessageBox
    :confirm-button="{ label: 'Continue', icon: 'i-lucide-arrow-right', color: 'info' }"
    :cancel-button="{ label: 'Cancel', variant: 'ghost' }"
  >
    <UButton variant="outline" label="Button Properties" />
  </MMessageBox>
</template>

dismissible Close Strategy

dismissible defaults to false (strict mode). When enabled, clicking the overlay or pressing Esc closes the dialog and marks it as unconfirmed via close(false):

<template>
  <MMessageBox dismissible>
    <UButton variant="outline" color="neutral" label="Close Strategy" />
  </MMessageBox>
</template>

Examples

Controlled State

Use v-model:open to control the open state externally — ideal for programmatic triggering and multi-button coordination:

<script setup lang="ts">
const open = ref(false)
const result = ref('')
</script>

<template>
  <div class="flex gap-2">
    <UButton variant="soft" @click="open = true">
      外部按钮打开
    </UButton>
    <UButton color="neutral" variant="outline" @click="open = false">
      外部按钮关闭
    </UButton>
    <span v-if="result" class="self-center text-sm text-muted">{{ result }}</span>

    <MMessageBox
      v-model:open="open"
      mode="confirm"
      type="primary"
      title="确认执行同步"
      :dismissible="false"
      :modal="false"
      description="open 由父组件持有,可被任意按钮、定时器或异步任务触发。"
      @close="(ok: boolean) => result = `受控 → ${ok}`"
    />
  </div>
</template>

Body Slot

The body slot renders rich text content. The close slot parameter allows programmatically closing the dialog from within the body:

<template>
  <MMessageBox
    mode="confirm"
    type="primary"
    title="服务条款更新"
  >
    <UButton color="primary" variant="soft" icon="i-lucide-file-text" label="阅读条款" />
    <template #body="{ close }">
      <p class="text-sm text-muted">
        我们对服务条款进行了以下更新,请仔细阅读:
      </p>
      <ul class="mt-2 space-y-1 text-sm list-disc list-inside text-muted">
        <li>数据收集范围已缩减</li>
        <li>用户隐私保护条款已加强</li>
        <li>退款政策已更新</li>
      </ul>
      <UButton
        class="mt-3"
        size="xs"
        variant="ghost"
        color="neutral"
        label="先取消,稍后阅读"
        @click="close"
      />
    </template>
  </MMessageBox>
</template>

Title Slot

The title slot fully takes over the title area, replacing the default icon-plus-text combination:

<template>
  <MMessageBox
    mode="confirm"
    type="primary"
    title="原标题文案"
    description="标题区由 #title 插槽决定,原 title prop 不会渲染。"
  >
    <UButton variant="outline" label="自定义标题" />
    <template #title>
      <UIcon name="i-lucide-sparkles" class="size-5 text-primary" />
      <span class="font-bold text-primary">完全自定义的标题样式</span>
      <UBadge color="primary" variant="subtle" label="NEW" />
    </template>
  </MMessageBox>
</template>

Description Slot

The description slot supports rich text descriptions and works alongside the title prop:

<template>
  <MMessageBox
    mode="alert"
    type="info"
    title="版本更新说明"
  >
    <UButton variant="outline" label="查看说明" />
    <template #description>
      <span class="text-sm">
        v2.0 已发布,详见
        <a href="#" class="text-primary underline">完整变更日志</a>
        ,或继续使用旧版。
      </span>
    </template>
  </MMessageBox>
</template>

Header Slot

The header slot fully takes over the title and description container, enabling custom layout and typography:

<template>
  <MMessageBox
    mode="confirm"
    type="warning"
    title="原标题"
    description="原描述"
  >
    <UButton variant="outline" label="自定义头部" />
    <template #header>
      <div class="flex items-center gap-3 p-4 bg-warning/10 rounded-t-lg">
        <UIcon name="i-lucide-triangle-alert" class="size-8 text-warning" />
        <div>
          <div class="font-semibold">
            高风险操作
          </div>
          <div class="text-xs text-muted">
            头部插槽自定义整块布局
          </div>
        </div>
      </div>
    </template>
  </MMessageBox>
</template>

The footer slot fully takes over the button area. The close slot parameter is used to close the dialog:

<template>
  <MMessageBox
    mode="confirm"
    type="primary"
    title="步进式确认"
    description="footer 插槽接管按钮区,可自由组合多按钮、分组、状态等。"
  >
    <UButton variant="outline" label="自定义操作" />
    <template #footer="{ close }">
      <UButton color="neutral" variant="ghost" label="稍后处理" @click="close" />
      <UButton color="warning" variant="soft" label="保留并继续" @click="close" />
      <UButton color="primary" label="立即应用" @click="close" />
    </template>
  </MMessageBox>
</template>

Close Button Slot

The close slot customizes the top-right close button — change icon, color, and styles:

<template>
  <MMessageBox
    mode="alert"
    type="info"
    title="自定义关闭按钮"
    description="close 插槽完全替换默认关闭按钮。"
  >
    <UButton variant="outline" label="查看" />
    <template #close>
      <UButton size="xs" color="error" variant="ghost" icon="i-lucide-x-circle" />
    </template>
  </MMessageBox>
</template>

Content Slot

The content slot replaces the entire header / body / footer layout — ideal for fully custom scenarios:

<template>
  <MMessageBox title="原标题">
    <UButton variant="soft" color="primary" label="极致定制" />
    <template #content="{ close }">
      <div class="p-6 flex flex-col items-center gap-4 text-center">
        <UIcon name="i-lucide-party-popper" class="size-12 text-primary" />
        <div class="text-lg font-semibold">
          恭喜达成成就
        </div>
        <p class="text-sm text-muted">
          content 插槽替代 header/body/footer 三段式,可完全自定义内部结构。
        </p>
        <UButton label="收下奖励" @click="close" />
      </div>
    </template>
  </MMessageBox>
</template>

Programmatic Usage

Use useMessageBox() to invoke dialogs from any logic without declaring the component in templates. alert() returns Promise<void>, and confirm() returns Promise<boolean>:

<script setup lang="ts">
const { alert, confirm } = useMessageBox()
const alertResult = ref('')
const confirmResult = ref('')

async function showAlert() {
  await alert({
    type: 'success',
    title: '操作成功',
    description: '数据已成功提交,await 会等待弹窗关闭后继续执行。'
  })
  alertResult.value = 'await 后的逻辑已执行'
}

async function showConfirm() {
  const ok = await confirm({
    type: 'error',
    title: '清空数据',
    description: '即将清空所有本地缓存,此操作不可撤销。',
    icon: 'i-lucide-database-zap',
    confirmButton: { color: 'error', label: '确认清空' },
    cancelButton: { label: '我再想想' }
  })
  confirmResult.value = ok ? '数据已清空' : '操作已取消'
}
</script>

<template>
  <div class="space-y-3">
    <div class="flex flex-wrap gap-3">
      <div class="flex items-center gap-3">
        <UButton
          color="success"
          variant="soft"
          label="alert()"
          icon="i-lucide-bell"
          @click="showAlert"
        />
        <span v-if="alertResult" class="text-sm text-muted">{{ alertResult }}</span>
      </div>
      <div class="flex items-center gap-3">
        <UButton
          color="error"
          variant="outline"
          label="confirm()"
          icon="i-lucide-database-zap"
          @click="showConfirm"
        />
        <span v-if="confirmResult" class="text-sm text-muted">{{ confirmResult }}</span>
      </div>
    </div>
  </div>
</template>

API

Props

Prop Default Type
title'提示'string

模态框标题文本。

type'primary'"primary" | "info" | "success" | "warning" | "error" | "neutral"

控制消息框的语义类型。 会影响默认图标与确认按钮颜色。

mode'alert'"alert" | "confirm"

控制消息框的操作模式。 alert 仅显示确认按钮,confirm 显示取消与确认按钮。

alertConfirmLabel'知道了'string

alert 模式下的确认按钮文本。

confirmLabel'确认'string

确认按钮文本。

cancelLabel'取消'string

取消按钮文本。

descriptionstring
contentDialogContentProps & Partial<EmitsToProps<DialogContentImplEmits>>

The content of the modal.

portaltruestring | false | true | HTMLElement

Render the modal in a portal.

closetrueboolean | Omit<ButtonProps, LinkPropsKeys>

Display a close button to dismiss the modal. { size: 'md', color: 'neutral', variant: 'ghost' }

closeIconappConfig.ui.icons.closeany

The icon displayed in the close button.

icon'i-lucide-circle-question-mark'any

标题前展示的图标名称。

confirmButtonButtonProps

透传给确认按钮的属性。 未显式指定 color 时会默认继承当前 type

cancelButtonButtonProps

透传给取消按钮的属性。 仅在 mode='confirm' 时渲染。

openboolean
dismissiblefalseboolean

false 时,点击遮罩层或按下 Esc 键将不会关闭模态框。

overlaytrueboolean

Render an overlay behind the modal.

scrollablefalseboolean

When true, enables scrollable overlay mode where content scrolls within the overlay.

transitiontrueboolean

Animate the modal when opening or closing.

fullscreenfalseboolean

When true, the modal will take up the full screen.

modalboolean

The modality of the dialog When set to true,
interaction with outside elements will be disabled and only dialog content will be visible to screen readers.

uiRecord<string, SlotClass> & { overlay?: SlotClass; content?: SlotClass; header?: SlotClass; wrapper?: SlotClass; body?: SlotClass; footer?: SlotClass; title?: SlotClass; description?: SlotClass; close?: SlotClass; icon?: SlotClass; }

Emits

Event Type
close[confirmed: boolean]
update:open[value: boolean]

Slots

Slot Type
default{ open: boolean; }
content{ close: () => void; }
header{ close: () => void; }
title{}
description{}
actions{}
close{ ui: { overlay: (props?: Record<string, any>) => string; content: (props?: Record<string, any>) => string; header: (props?: Record<string, any>) => string; wrapper: (props?: Record<string, any>) => string; body: (props?: Record<string, any>) => string; footer: (props?: Record<string, any>) => string; title: (props?: Record<string, any>) => string; description: (props?: Record<string, any>) => string; close: (props?: Record<string, any>) => string; }; }
body{ close: () => void; }
footer{ close: () => void; }

Theme

app.config.ts
export default defineAppConfig({
  ui: {
    messageBox: {
      slots: {
        title: 'flex gap-2 items-center',
        footer: 'justify-end',
        icon: 'size-5 shrink-0'
      },
      variants: {
        type: {
          primary: {
            icon: 'text-primary'
          },
          info: {
            icon: 'text-info'
          },
          success: {
            icon: 'text-success'
          },
          warning: {
            icon: 'text-warning'
          },
          error: {
            icon: 'text-error'
          },
          neutral: {
            icon: 'text-muted'
          }
        }
      }
    }
  }
})

Changelog

No recent changes
Copyright © 2025 - 2026 YiXuan - MIT License